diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-04-02 08:55:10 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-04-02 08:55:10 +0000 |
commit | 07b2cfcdb817cc0790420f159a313d61e7241cb9 (patch) | |
tree | d374cdca417e76f1bf101f139dba2db1d10ee8f7 /lib | |
parent | 1e255aab650a7fa2047fd953cae65b12215280af (diff) | |
download | FreeBSD-src-07b2cfcdb817cc0790420f159a313d61e7241cb9.zip FreeBSD-src-07b2cfcdb817cc0790420f159a313d61e7241cb9.tar.gz |
Update clang to r100181.
Diffstat (limited to 'lib')
163 files changed, 7485 insertions, 5603 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7f5c9b1..c77acce 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -45,7 +45,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), - BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { + BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts), + LastSDM(0, 0) { ObjCIdRedefinitionType = QualType(); ObjCClassRedefinitionType = QualType(); ObjCSelRedefinitionType = QualType(); @@ -858,34 +859,22 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, } } -unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) { - unsigned count = 0; - for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(), - E = PD->prop_end(); I != E; ++I) - if ((*I)->getPropertyIvarDecl()) - ++count; - - // Also look into nested protocols. - for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(), - E = PD->protocol_end(); P != E; ++P) - count += CountProtocolSynthesizedIvars(*P); - return count; -} - -unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) { - unsigned count = 0; - for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(), - E = OI->prop_end(); I != E; ++I) { - if ((*I)->getPropertyIvarDecl()) +unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) { + unsigned count = 0; + // Count ivars declared in class extension. + if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) { + for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), + E = CDecl->ivar_end(); I != E; ++I) { ++count; + } } - // Also look into interface's protocol list for properties declared - // in the protocol and whose ivars are synthesized. - for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), - PE = OI->protocol_end(); P != PE; ++P) { - ObjCProtocolDecl *PD = (*P); - count += CountProtocolSynthesizedIvars(PD); - } + + // Count ivar defined in this class's implementation. This + // includes synthesized ivars. + if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) + for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), + E = ImplDecl->ivar_end(); I != E; ++I) + ++count; return count; } @@ -966,7 +955,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, // Add in synthesized ivar count if laying out an implementation. if (Impl) { - unsigned SynthCount = CountSynthesizedIvars(D); + unsigned SynthCount = CountNonClassIvars(D); // If there aren't any sythesized ivars then reuse the interface // entry. Note we can't cache this because we simply free all // entries later; however we shouldn't look up implementations @@ -1108,14 +1097,12 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } -static QualType getNoReturnCallConvType(ASTContext& Context, QualType T, - bool AddNoReturn, - CallingConv CallConv) { +static QualType getExtFunctionType(ASTContext& Context, QualType T, + const FunctionType::ExtInfo &Info) { QualType ResultType; if (const PointerType *Pointer = T->getAs<PointerType>()) { QualType Pointee = Pointer->getPointeeType(); - ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn, - CallConv); + ResultType = getExtFunctionType(Context, Pointee, Info); if (ResultType == Pointee) return T; @@ -1123,19 +1110,18 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T, } else if (const BlockPointerType *BlockPointer = T->getAs<BlockPointerType>()) { QualType Pointee = BlockPointer->getPointeeType(); - ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn, - CallConv); + ResultType = getExtFunctionType(Context, Pointee, Info); if (ResultType == Pointee) return T; ResultType = Context.getBlockPointerType(ResultType); } else if (const FunctionType *F = T->getAs<FunctionType>()) { - if (F->getNoReturnAttr() == AddNoReturn && F->getCallConv() == CallConv) + if (F->getExtInfo() == Info) return T; if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) { ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(), - AddNoReturn, CallConv); + Info); } else { const FunctionProtoType *FPT = cast<FunctionProtoType>(F); ResultType @@ -1146,7 +1132,7 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T, FPT->hasAnyExceptionSpec(), FPT->getNumExceptions(), FPT->exception_begin(), - AddNoReturn, CallConv); + Info); } } else return T; @@ -1155,11 +1141,21 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T, } QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { - return getNoReturnCallConvType(*this, T, AddNoReturn, T.getCallConv()); + FunctionType::ExtInfo Info = getFunctionExtInfo(T); + return getExtFunctionType(*this, T, + Info.withNoReturn(AddNoReturn)); } QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) { - return getNoReturnCallConvType(*this, T, T.getNoReturnAttr(), CallConv); + FunctionType::ExtInfo Info = getFunctionExtInfo(T); + return getExtFunctionType(*this, T, + Info.withCallingConv(CallConv)); +} + +QualType ASTContext::getRegParmType(QualType T, unsigned RegParm) { + FunctionType::ExtInfo Info = getFunctionExtInfo(T); + return getExtFunctionType(*this, T, + Info.withRegParm(RegParm)); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -1617,12 +1613,13 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// -QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, - CallingConv CallConv) { +QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, + const FunctionType::ExtInfo &Info) { + const CallingConv CallConv = Info.getCC(); // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; - FunctionNoProtoType::Profile(ID, ResultTy, NoReturn, CallConv); + FunctionNoProtoType::Profile(ID, ResultTy, Info); void *InsertPos = 0; if (FunctionNoProtoType *FT = @@ -1632,8 +1629,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, QualType Canonical; if (!ResultTy.isCanonical() || getCanonicalCallConv(CallConv) != CallConv) { - Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn, - getCanonicalCallConv(CallConv)); + Canonical = + getFunctionNoProtoType(getCanonicalType(ResultTy), + Info.withCallingConv(getCanonicalCallConv(CallConv))); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -1642,7 +1640,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, } FunctionNoProtoType *New = new (*this, TypeAlignment) - FunctionNoProtoType(ResultTy, Canonical, NoReturn, CallConv); + FunctionNoProtoType(ResultTy, Canonical, Info); Types.push_back(New); FunctionNoProtoTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1654,14 +1652,15 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool hasAnyExceptionSpec, unsigned NumExs, - const QualType *ExArray, bool NoReturn, - CallingConv CallConv) { + const QualType *ExArray, + const FunctionType::ExtInfo &Info) { + const CallingConv CallConv= Info.getCC(); // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - NumExs, ExArray, NoReturn, CallConv); + NumExs, ExArray, Info); void *InsertPos = 0; if (FunctionProtoType *FTP = @@ -1686,8 +1685,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, isVariadic, TypeQuals, false, - false, 0, 0, NoReturn, - getCanonicalCallConv(CallConv)); + false, 0, 0, + Info.withCallingConv(getCanonicalCallConv(CallConv))); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -1704,7 +1703,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, NumExs*sizeof(QualType), TypeAlignment); new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - ExArray, NumExs, Canonical, NoReturn, CallConv); + ExArray, NumExs, Canonical, Info); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -1963,66 +1962,76 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS, return QualType(T, 0); } -QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, - const IdentifierInfo *Name, - QualType Canon) { +QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + QualType Canon) { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); if (Canon.isNull()) { NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); - if (CanonNNS != NNS) - Canon = getTypenameType(CanonNNS, Name); + ElaboratedTypeKeyword CanonKeyword = Keyword; + if (Keyword == ETK_None) + CanonKeyword = ETK_Typename; + + if (CanonNNS != NNS || CanonKeyword != Keyword) + Canon = getDependentNameType(CanonKeyword, CanonNNS, Name); } llvm::FoldingSetNodeID ID; - TypenameType::Profile(ID, NNS, Name); + DependentNameType::Profile(ID, Keyword, NNS, Name); void *InsertPos = 0; - TypenameType *T - = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentNameType *T + = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); - T = new (*this) TypenameType(NNS, Name, Canon); + T = new (*this) DependentNameType(Keyword, NNS, Name, Canon); Types.push_back(T); - TypenameTypes.InsertNode(T, InsertPos); + DependentNameTypes.InsertNode(T, InsertPos); return QualType(T, 0); } QualType -ASTContext::getTypenameType(NestedNameSpecifier *NNS, - const TemplateSpecializationType *TemplateId, - QualType Canon) { +ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const TemplateSpecializationType *TemplateId, + QualType Canon) { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); llvm::FoldingSetNodeID ID; - TypenameType::Profile(ID, NNS, TemplateId); + DependentNameType::Profile(ID, Keyword, NNS, TemplateId); void *InsertPos = 0; - TypenameType *T - = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentNameType *T + = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); if (Canon.isNull()) { NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); QualType CanonType = getCanonicalType(QualType(TemplateId, 0)); - if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) { + ElaboratedTypeKeyword CanonKeyword = Keyword; + if (Keyword == ETK_None) + CanonKeyword = ETK_Typename; + if (CanonNNS != NNS || CanonKeyword != Keyword || + CanonType != QualType(TemplateId, 0)) { const TemplateSpecializationType *CanonTemplateId = CanonType->getAs<TemplateSpecializationType>(); assert(CanonTemplateId && "Canonical type must also be a template specialization type"); - Canon = getTypenameType(CanonNNS, CanonTemplateId); + Canon = getDependentNameType(CanonKeyword, CanonNNS, CanonTemplateId); } - TypenameType *CheckT - = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentNameType *CheckT + = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!CheckT && "Typename canonical type is broken"); (void)CheckT; } - T = new (*this) TypenameType(NNS, TemplateId, Canon); + T = new (*this) DependentNameType(Keyword, NNS, TemplateId, Canon); Types.push_back(T); - TypenameTypes.InsertNode(T, InsertPos); + DependentNameTypes.InsertNode(T, InsertPos); return QualType(T, 0); } @@ -4127,14 +4136,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, bool ASTContext::canAssignObjCInterfacesInBlockPointer( const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT) { - if (RHSOPT->isObjCBuiltinType()) + if (RHSOPT->isObjCBuiltinType() || + LHSOPT->isObjCIdType() || LHSOPT->isObjCQualifiedIdType()) return true; if (LHSOPT->isObjCBuiltinType()) { return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType(); } - if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) + if (RHSOPT->isObjCQualifiedIdType()) return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), QualType(RHSOPT,0), false); @@ -4315,13 +4325,22 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType())) allRTypes = false; // FIXME: double check this - bool NoReturn = lbase->getNoReturnAttr() || rbase->getNoReturnAttr(); - if (NoReturn != lbase->getNoReturnAttr()) + // FIXME: should we error if lbase->getRegParmAttr() != 0 && + // rbase->getRegParmAttr() != 0 && + // lbase->getRegParmAttr() != rbase->getRegParmAttr()? + FunctionType::ExtInfo lbaseInfo = lbase->getExtInfo(); + FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo(); + unsigned RegParm = lbaseInfo.getRegParm() == 0 ? rbaseInfo.getRegParm() : + lbaseInfo.getRegParm(); + bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); + if (NoReturn != lbaseInfo.getNoReturn() || + RegParm != lbaseInfo.getRegParm()) allLTypes = false; - if (NoReturn != rbase->getNoReturnAttr()) + if (NoReturn != rbaseInfo.getNoReturn() || + RegParm != rbaseInfo.getRegParm()) allRTypes = false; - CallingConv lcc = lbase->getCallConv(); - CallingConv rcc = rbase->getCallConv(); + CallingConv lcc = lbaseInfo.getCC(); + CallingConv rcc = rbaseInfo.getCC(); // Compatible functions must have compatible calling conventions if (!isSameCallConv(lcc, rcc)) return QualType(); @@ -4360,7 +4379,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (allRTypes) return rhs; return getFunctionType(retType, types.begin(), types.size(), lproto->isVariadic(), lproto->getTypeQuals(), - false, false, 0, 0, NoReturn, lcc); + false, false, 0, 0, + FunctionType::ExtInfo(NoReturn, RegParm, lcc)); } if (lproto) allRTypes = false; @@ -4393,13 +4413,15 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (allRTypes) return rhs; return getFunctionType(retType, proto->arg_type_begin(), proto->getNumArgs(), proto->isVariadic(), - proto->getTypeQuals(), - false, false, 0, 0, NoReturn, lcc); + proto->getTypeQuals(), + false, false, 0, 0, + FunctionType::ExtInfo(NoReturn, RegParm, lcc)); } if (allLTypes) return lhs; if (allRTypes) return rhs; - return getFunctionNoProtoType(retType, NoReturn, lcc); + FunctionType::ExtInfo Info(NoReturn, RegParm, lcc); + return getFunctionNoProtoType(retType, Info); } QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, @@ -4903,7 +4925,7 @@ QualType ASTContext::GetBuiltinType(unsigned id, // FIXME: Should we create noreturn types? return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), TypeStr[0] == '.', 0, false, false, 0, 0, - false, CC_Default); + FunctionType::ExtInfo()); } QualType diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index dd2528a..75cf138 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -73,7 +73,7 @@ namespace { // FIXME: SubstTemplateTypeParmType // FIXME: TemplateSpecializationType QualType VisitQualifiedNameType(QualifiedNameType *T); - // FIXME: TypenameType + // FIXME: DependentNameType QualType VisitObjCInterfaceType(ObjCInterfaceType *T); QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T); @@ -484,10 +484,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Function1->getResultType(), Function2->getResultType())) return false; - if (Function1->getNoReturnAttr() != Function2->getNoReturnAttr()) - return false; - if (Function1->getCallConv() != Function2->getCallConv()) - return false; + if (Function1->getExtInfo() != Function2->getExtInfo()) + return false; break; } @@ -620,9 +618,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } - case Type::Typename: { - const TypenameType *Typename1 = cast<TypenameType>(T1); - const TypenameType *Typename2 = cast<TypenameType>(T2); + case Type::DependentName: { + const DependentNameType *Typename1 = cast<DependentNameType>(T1); + const DependentNameType *Typename2 = cast<DependentNameType>(T2); if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(), Typename2->getQualifier())) @@ -1200,10 +1198,9 @@ QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) { QualType ToResultType = Importer.Import(T->getResultType()); if (ToResultType.isNull()) return QualType(); - + return Importer.getToContext().getFunctionNoProtoType(ToResultType, - T->getNoReturnAttr(), - T->getCallConv()); + T->getExtInfo()); } QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) { @@ -1241,8 +1238,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) { T->hasAnyExceptionSpec(), ExceptionTypes.size(), ExceptionTypes.data(), - T->getNoReturnAttr(), - T->getCallConv()); + T->getExtInfo()); } QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) { diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 3408a1e..91aaddc 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_library(clangAST AttrImpl.cpp CXXInheritance.cpp Decl.cpp + DeclarationName.cpp DeclBase.cpp DeclCXX.cpp DeclFriend.cpp @@ -16,10 +17,9 @@ add_clang_library(clangAST DeclObjC.cpp DeclPrinter.cpp DeclTemplate.cpp - DeclarationName.cpp Expr.cpp - ExprCXX.cpp ExprConstant.cpp + ExprCXX.cpp FullExpr.cpp InheritViz.cpp NestedNameSpecifier.cpp diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 70f8ee4..a9f2230 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -416,3 +416,240 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, return false; } + +void OverridingMethods::add(unsigned OverriddenSubobject, + UniqueVirtualMethod Overriding) { + llvm::SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides + = Overrides[OverriddenSubobject]; + if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(), + Overriding) == SubobjectOverrides.end()) + SubobjectOverrides.push_back(Overriding); +} + +void OverridingMethods::add(const OverridingMethods &Other) { + for (const_iterator I = Other.begin(), IE = Other.end(); I != IE; ++I) { + for (overriding_const_iterator M = I->second.begin(), + MEnd = I->second.end(); + M != MEnd; + ++M) + add(I->first, *M); + } +} + +void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) { + for (iterator I = begin(), IEnd = end(); I != IEnd; ++I) { + I->second.clear(); + I->second.push_back(Overriding); + } +} + + +namespace { + class FinalOverriderCollector { + /// \brief The number of subobjects of a given class type that + /// occur within the class hierarchy. + llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount; + + /// \brief Overriders for each virtual base subobject. + llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders; + + CXXFinalOverriderMap FinalOverriders; + + public: + ~FinalOverriderCollector(); + + void Collect(const CXXRecordDecl *RD, bool VirtualBase, + const CXXRecordDecl *InVirtualSubobject, + CXXFinalOverriderMap &Overriders); + }; +} + +void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, + bool VirtualBase, + const CXXRecordDecl *InVirtualSubobject, + CXXFinalOverriderMap &Overriders) { + unsigned SubobjectNumber = 0; + if (!VirtualBase) + SubobjectNumber + = ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())]; + + for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), + BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) { + if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { + const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (!BaseDecl->isPolymorphic()) + continue; + + if (Overriders.empty() && !Base->isVirtual()) { + // There are no other overriders of virtual member functions, + // so let the base class fill in our overriders for us. + Collect(BaseDecl, false, InVirtualSubobject, Overriders); + continue; + } + + // Collect all of the overridders from the base class subobject + // and merge them into the set of overridders for this class. + // For virtual base classes, populate or use the cached virtual + // overrides so that we do not walk the virtual base class (and + // its base classes) more than once. + CXXFinalOverriderMap ComputedBaseOverriders; + CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders; + if (Base->isVirtual()) { + CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl]; + if (!MyVirtualOverriders) { + MyVirtualOverriders = new CXXFinalOverriderMap; + Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders); + } + + BaseOverriders = MyVirtualOverriders; + } else + Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders); + + // Merge the overriders from this base class into our own set of + // overriders. + for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(), + OMEnd = BaseOverriders->end(); + OM != OMEnd; + ++OM) { + const CXXMethodDecl *CanonOM + = cast<CXXMethodDecl>(OM->first->getCanonicalDecl()); + Overriders[CanonOM].add(OM->second); + } + } + } + + for (CXXRecordDecl::method_iterator M = RD->method_begin(), + MEnd = RD->method_end(); + M != MEnd; + ++M) { + // We only care about virtual methods. + if (!M->isVirtual()) + continue; + + CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl()); + + if (CanonM->begin_overridden_methods() + == CanonM->end_overridden_methods()) { + // This is a new virtual function that does not override any + // other virtual function. Add it to the map of virtual + // functions for which we are tracking overridders. + + // C++ [class.virtual]p2: + // For convenience we say that any virtual function overrides itself. + Overriders[CanonM].add(SubobjectNumber, + UniqueVirtualMethod(CanonM, SubobjectNumber, + InVirtualSubobject)); + continue; + } + + // This virtual method overrides other virtual methods, so it does + // not add any new slots into the set of overriders. Instead, we + // replace entries in the set of overriders with the new + // overrider. To do so, we dig down to the original virtual + // functions using data recursion and update all of the methods it + // overrides. + typedef std::pair<CXXMethodDecl::method_iterator, + CXXMethodDecl::method_iterator> OverriddenMethods; + llvm::SmallVector<OverriddenMethods, 4> Stack; + Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(), + CanonM->end_overridden_methods())); + while (!Stack.empty()) { + OverriddenMethods OverMethods = Stack.back(); + Stack.pop_back(); + + for (; OverMethods.first != OverMethods.second; ++OverMethods.first) { + const CXXMethodDecl *CanonOM + = cast<CXXMethodDecl>((*OverMethods.first)->getCanonicalDecl()); + if (CanonOM->begin_overridden_methods() + == CanonOM->end_overridden_methods()) { + // C++ [class.virtual]p2: + // A virtual member function C::vf of a class object S is + // a final overrider unless the most derived class (1.8) + // of which S is a base class subobject (if any) declares + // or inherits another member function that overrides vf. + // + // Treating this object like the most derived class, we + // replace any overrides from base classes with this + // overriding virtual function. + Overriders[CanonOM].replaceAll( + UniqueVirtualMethod(CanonM, SubobjectNumber, + InVirtualSubobject)); + continue; + } + + // Continue recursion to the methods that this virtual method + // overrides. + Stack.push_back(std::make_pair(CanonOM->begin_overridden_methods(), + CanonOM->end_overridden_methods())); + } + } + } +} + +FinalOverriderCollector::~FinalOverriderCollector() { + for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator + VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end(); + VO != VOEnd; + ++VO) + delete VO->second; +} + +void +CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { + FinalOverriderCollector Collector; + Collector.Collect(this, false, 0, FinalOverriders); + + // Weed out any final overriders that come from virtual base class + // subobjects that were hidden by other subobjects along any path. + // This is the final-overrider variant of C++ [class.member.lookup]p10. + for (CXXFinalOverriderMap::iterator OM = FinalOverriders.begin(), + OMEnd = FinalOverriders.end(); + OM != OMEnd; + ++OM) { + for (OverridingMethods::iterator SO = OM->second.begin(), + SOEnd = OM->second.end(); + SO != SOEnd; + ++SO) { + llvm::SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second; + if (Overriding.size() < 2) + continue; + + for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator + Pos = Overriding.begin(), PosEnd = Overriding.end(); + Pos != PosEnd; + /* increment in loop */) { + if (!Pos->InVirtualSubobject) { + ++Pos; + continue; + } + + // We have an overriding method in a virtual base class + // subobject (or non-virtual base class subobject thereof); + // determine whether there exists an other overriding method + // in a base class subobject that hides the virtual base class + // subobject. + bool Hidden = false; + for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator + OP = Overriding.begin(), OPEnd = Overriding.end(); + OP != OPEnd && !Hidden; + ++OP) { + if (Pos == OP) + continue; + + if (OP->Method->getParent()->isVirtuallyDerivedFrom( + const_cast<CXXRecordDecl *>(Pos->InVirtualSubobject))) + Hidden = true; + } + + if (Hidden) { + // The current overriding function is hidden by another + // overriding function; remove this one. + Pos = Overriding.erase(Pos); + PosEnd = Overriding.end(); + } else { + ++Pos; + } + } + } + } +} diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 6c9a45e..dc9fb59 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1413,10 +1413,8 @@ void TagDecl::startDefinition() { CXXRecordDecl *D = cast<CXXRecordDecl>(this); struct CXXRecordDecl::DefinitionData *Data = new (getASTContext()) struct CXXRecordDecl::DefinitionData(D); - do { - D->DefinitionData = Data; - D = cast_or_null<CXXRecordDecl>(D->getPreviousDeclaration()); - } while (D); + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) + cast<CXXRecordDecl>(*I)->DefinitionData = Data; } } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 1aac7cf..c693e15 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DependentDiagnostic.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" @@ -481,7 +482,7 @@ DeclContext::~DeclContext() { // FIXME: Currently ~ASTContext will delete the StoredDeclsMaps because // ~DeclContext() is not guaranteed to be called when ASTContext uses // a BumpPtrAllocator. - // delete static_cast<StoredDeclsMap*>(LookupPtr); + // delete LookupPtr; } void DeclContext::DestroyDecls(ASTContext &C) { @@ -516,10 +517,16 @@ bool DeclContext::isDependentContext() const { if (Record->getDescribedClassTemplate()) return true; - if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) { if (Function->getDescribedFunctionTemplate()) return true; + // Friend function declarations are dependent if their *lexical* + // context is dependent. + if (cast<Decl>(this)->getFriendObjectKind()) + return getLexicalParent()->isDependentContext(); + } + return getParent() && getParent()->isDependentContext(); } @@ -666,9 +673,7 @@ DeclContext::LoadVisibleDeclsFromExternalStorage() const { // Load the declaration IDs for all of the names visible in this // context. assert(!LookupPtr && "Have a lookup map before de-serialization?"); - StoredDeclsMap *Map = - (StoredDeclsMap*) getParentASTContext().CreateStoredDeclsMap(); - LookupPtr = Map; + StoredDeclsMap *Map = CreateStoredDeclsMap(getParentASTContext()); for (unsigned I = 0, N = Decls.size(); I != N; ++I) { (*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations); } @@ -727,10 +732,9 @@ void DeclContext::removeDecl(Decl *D) { if (isa<NamedDecl>(D)) { NamedDecl *ND = cast<NamedDecl>(D); - void *OpaqueMap = getPrimaryContext()->LookupPtr; - if (!OpaqueMap) return; + StoredDeclsMap *Map = getPrimaryContext()->LookupPtr; + if (!Map) return; - StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(OpaqueMap); StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); assert(Pos != Map->end() && "no lookup entry for decl"); Pos->second.remove(ND); @@ -808,9 +812,8 @@ DeclContext::lookup(DeclarationName Name) { return lookup_result(0, 0); } - StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr); - StoredDeclsMap::iterator Pos = Map->find(Name); - if (Pos == Map->end()) + StoredDeclsMap::iterator Pos = LookupPtr->find(Name); + if (Pos == LookupPtr->end()) return lookup_result(0, 0); return Pos->second.getLookupResult(getParentASTContext()); } @@ -878,12 +881,11 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { ASTContext *C = 0; if (!LookupPtr) { C = &getParentASTContext(); - LookupPtr = (StoredDeclsMap*) C->CreateStoredDeclsMap(); + CreateStoredDeclsMap(*C); } // Insert this declaration into the map. - StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr); - StoredDeclsList &DeclNameEntries = Map[D->getDeclName()]; + StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()]; if (DeclNameEntries.isNull()) { DeclNameEntries.setOnlyValue(D); return; @@ -952,13 +954,69 @@ void StoredDeclsList::materializeDecls(ASTContext &Context) { // Creation and Destruction of StoredDeclsMaps. // //===----------------------------------------------------------------------===// -void *ASTContext::CreateStoredDeclsMap() { - StoredDeclsMap *M = new StoredDeclsMap(); - SDMs.push_back(M); +StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const { + assert(!LookupPtr && "context already has a decls map"); + assert(getPrimaryContext() == this && + "creating decls map on non-primary context"); + + StoredDeclsMap *M; + bool Dependent = isDependentContext(); + if (Dependent) + M = new DependentStoredDeclsMap(); + else + M = new StoredDeclsMap(); + M->Previous = C.LastSDM; + C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent); + LookupPtr = M; return M; } void ASTContext::ReleaseDeclContextMaps() { - for (std::vector<void*>::iterator I = SDMs.begin(), E = SDMs.end(); I!=E; ++I) - delete (StoredDeclsMap*) *I; + // It's okay to delete DependentStoredDeclsMaps via a StoredDeclsMap + // pointer because the subclass doesn't add anything that needs to + // be deleted. + + StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt()); +} + +void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) { + while (Map) { + // Advance the iteration before we invalidate memory. + llvm::PointerIntPair<StoredDeclsMap*,1> Next = Map->Previous; + + if (Dependent) + delete static_cast<DependentStoredDeclsMap*>(Map); + else + delete Map; + + Map = Next.getPointer(); + Dependent = Next.getInt(); + } +} + +DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C, + DeclContext *Parent, + const PartialDiagnostic &PDiag) { + assert(Parent->isDependentContext() + && "cannot iterate dependent diagnostics of non-dependent context"); + Parent = Parent->getPrimaryContext(); + if (!Parent->LookupPtr) + Parent->CreateStoredDeclsMap(C); + + DependentStoredDeclsMap *Map + = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr); + + // Allocate the copy of the PartialDiagnostic via the ASTContext's + // BumpPtrAllocator, rather than the ASTContext itself. + PartialDiagnostic::Storage *DiagStorage = 0; + if (PDiag.hasStorage()) + DiagStorage = new (C) PartialDiagnostic::Storage; + + DependentDiagnostic *DD = new (C) DependentDiagnostic(PDiag, DiagStorage); + + // TODO: Maybe we shouldn't reverse the order during insertion. + DD->NextDiagnostic = Map->FirstDiagnostic; + Map->FirstDiagnostic = DD; + + return DD; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 37f7479..94ed85c 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -83,9 +83,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (data().Bases) C.Deallocate(data().Bases); - int vbaseCount = 0; - llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases; - bool hasDirectVirtualBase = false; + // The set of seen virtual base types. + llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes; + + // The virtual bases of this class. + llvm::SmallVector<const CXXBaseSpecifier *, 8> VBases; data().Bases = new(C) CXXBaseSpecifier [NumBases]; data().NumBases = NumBases; @@ -99,58 +101,44 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); - if (Base->isVirtual()) - hasDirectVirtualBase = true; + + // Now go through all virtual bases of this base and add them. for (CXXRecordDecl::base_class_iterator VBase = BaseClassDecl->vbases_begin(), E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) { - // Add this vbase to the array of vbases for current class if it is - // not already in the list. - // FIXME. Note that we do a linear search as number of such classes are - // very few. - int i; - for (i = 0; i < vbaseCount; ++i) - if (UniqueVbases[i]->getType() == VBase->getType()) - break; - if (i == vbaseCount) { - UniqueVbases.push_back(VBase); - ++vbaseCount; - } + // Add this base if it's not already in the list. + if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) + VBases.push_back(VBase); } - } - if (hasDirectVirtualBase) { - // Iterate one more time through the direct bases and add the virtual - // base to the list of vritual bases for current class. - for (unsigned i = 0; i < NumBases; ++i) { - const CXXBaseSpecifier *VBase = Bases[i]; - if (!VBase->isVirtual()) - continue; - int j; - for (j = 0; j < vbaseCount; ++j) - if (UniqueVbases[j]->getType() == VBase->getType()) - break; - if (j == vbaseCount) { - UniqueVbases.push_back(VBase); - ++vbaseCount; - } + + if (Base->isVirtual()) { + // Add this base if it's not already in the list. + if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType))) + VBases.push_back(Base); } + } - if (vbaseCount > 0) { - // build AST for inhireted, direct or indirect, virtual bases. - data().VBases = new (C) CXXBaseSpecifier [vbaseCount]; - data().NumVBases = vbaseCount; - for (int i = 0; i < vbaseCount; i++) { - QualType QT = UniqueVbases[i]->getType(); - // Skip dependent types; we can't do any checking on them now. - if (QT->isDependentType()) - continue; - CXXRecordDecl *VBaseClassDecl - = cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl()); - data().VBases[i] = - CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, - VBaseClassDecl->getTagKind() == RecordDecl::TK_class, - UniqueVbases[i]->getAccessSpecifier(), QT); - } + + if (VBases.empty()) + return; + + // Create base specifier for any direct or indirect virtual bases. + data().VBases = new (C) CXXBaseSpecifier[VBases.size()]; + data().NumVBases = VBases.size(); + for (int I = 0, E = VBases.size(); I != E; ++I) { + QualType VBaseType = VBases[I]->getType(); + + // Skip dependent types; we can't do any checking on them now. + if (VBaseType->isDependentType()) + continue; + + CXXRecordDecl *VBaseClassDecl + = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl()); + + data().VBases[I] = + CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, + VBaseClassDecl->getTagKind() == RecordDecl::TK_class, + VBases[I]->getAccessSpecifier(), VBaseType); } } @@ -320,6 +308,8 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { QualType T; + if (isa<UsingShadowDecl>(Conv)) + Conv = cast<UsingShadowDecl>(Conv)->getTargetDecl(); if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv)) T = ConvTemp->getTemplatedDecl()->getResultType(); else @@ -457,26 +447,45 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { return &data().VisibleConversions; } -void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) { - assert(!ConvDecl->getDescribedFunctionTemplate() && - "Conversion function templates should cast to FunctionTemplateDecl."); +#ifndef NDEBUG +void CXXRecordDecl::CheckConversionFunction(NamedDecl *ConvDecl) { assert(ConvDecl->getDeclContext() == this && "conversion function does not belong to this record"); - // We intentionally don't use the decl's access here because it - // hasn't been set yet. That's really just a misdesign in Sema. - data().Conversions.addDecl(ConvDecl); + ConvDecl = ConvDecl->getUnderlyingDecl(); + if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(ConvDecl)) { + assert(isa<CXXConversionDecl>(Temp->getTemplatedDecl())); + } else { + assert(isa<CXXConversionDecl>(ConvDecl)); + } } +#endif + +void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { + // This operation is O(N) but extremely rare. Sema only uses it to + // remove UsingShadowDecls in a class that were followed by a direct + // declaration, e.g.: + // class A : B { + // using B::operator int; + // operator int(); + // }; + // This is uncommon by itself and even more uncommon in conjunction + // with sufficiently large numbers of directly-declared conversions + // that asymptotic behavior matters. + + UnresolvedSetImpl &Convs = *getConversionFunctions(); + for (unsigned I = 0, E = Convs.size(); I != E; ++I) { + if (Convs[I].getDecl() == ConvDecl) { + Convs.erase(I); + assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end() + && "conversion was found multiple times in unresolved set"); + return; + } + } -void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { - assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && - "Function template is not a conversion function template"); - assert(ConvDecl->getDeclContext() == this && - "conversion function does not belong to this record"); - data().Conversions.addDecl(ConvDecl); + llvm_unreachable("conversion not found in set!"); } - void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) { Method->setVirtualAsWritten(true); setAggregate(false); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 6a71e92..6764612 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -492,44 +492,45 @@ QualType CallExpr::getCallReturnType() const { return FnType->getResultType(); } -MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, - SourceRange qualrange, ValueDecl *memberdecl, - SourceLocation l, const TemplateArgumentListInfo *targs, - QualType ty) - : Expr(MemberExprClass, ty, - base->isTypeDependent() || (qual && qual->isDependent()), - base->isValueDependent() || (qual && qual->isDependent())), - Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), - HasQualifier(qual != 0), HasExplicitTemplateArgumentList(targs) { - // Initialize the qualifier, if any. - if (HasQualifier) { - NameQualifier *NQ = getMemberQualifier(); - NQ->NNS = qual; - NQ->Range = qualrange; - } - - // Initialize the explicit template argument list, if any. - if (targs) - getExplicitTemplateArgumentList()->initializeFrom(*targs); -} - MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, ValueDecl *memberdecl, + NamedDecl *founddecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty) { std::size_t Size = sizeof(MemberExpr); - if (qual != 0) - Size += sizeof(NameQualifier); + + bool hasQualOrFound = (qual != 0 || founddecl != memberdecl); + if (hasQualOrFound) + Size += sizeof(MemberNameQualifier); if (targs) Size += ExplicitTemplateArgumentList::sizeFor(*targs); void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>()); - return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, - targs, ty); + MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, l, ty); + + if (hasQualOrFound) { + if (qual && qual->isDependent()) { + E->setValueDependent(true); + E->setTypeDependent(true); + } + E->HasQualifierOrFoundDecl = true; + + MemberNameQualifier *NQ = E->getMemberQualifier(); + NQ->NNS = qual; + NQ->Range = qualrange; + NQ->FoundDecl = founddecl; + } + + if (targs) { + E->HasExplicitTemplateArgumentList = true; + E->getExplicitTemplateArgumentList()->initializeFrom(*targs); + } + + return E; } const char *CastExpr::getCastKindName() const { @@ -544,6 +545,8 @@ const char *CastExpr::getCastKindName() const { return "BaseToDerived"; case CastExpr::CK_DerivedToBase: return "DerivedToBase"; + case CastExpr::CK_UncheckedDerivedToBase: + return "UncheckedDerivedToBase"; case CastExpr::CK_Dynamic: return "Dynamic"; case CastExpr::CK_ToUnion: @@ -914,8 +917,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case CXXConstructExprClass: return false; - case ObjCMessageExprClass: + case ObjCMessageExprClass: { + const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this); + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (MD && MD->getAttr<WarnUnusedResultAttr>()) { + Loc = getExprLoc(); + return true; + } return false; + } case ObjCImplicitSetterGetterRefExprClass: { // Dot syntax for message send. #if 0 diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 8a64f8e..27a277d 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -750,7 +750,7 @@ bool Type::isSpecifierType() const { case SubstTemplateTypeParm: case TemplateSpecialization: case QualifiedName: - case Typename: + case DependentName: case ObjCInterface: case ObjCObjectPointer: case Elaborated: @@ -760,6 +760,27 @@ bool Type::isSpecifierType() const { } } +bool Type::isElaboratedTypeSpecifier() const { + if (getTypeClass() == Elaborated) + return true; + + if (const DependentNameType *Dependent = dyn_cast<DependentNameType>(this)) { + switch (Dependent->getKeyword()) { + case ETK_None: + case ETK_Typename: + return false; + + case ETK_Class: + case ETK_Struct: + case ETK_Union: + case ETK_Enum: + return true; + } + } + + return false; +} + const char *Type::getTypeClassName() const { switch (TC) { default: assert(0 && "Type class not in TypeNodes.def!"); @@ -820,8 +841,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool anyExceptionSpec, unsigned NumExceptions, - exception_iterator Exs, bool NoReturn, - CallingConv CallConv) { + exception_iterator Exs, + const FunctionType::ExtInfo &Info) { ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); @@ -833,15 +854,16 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, for (unsigned i = 0; i != NumExceptions; ++i) ID.AddPointer(Exs[i].getAsOpaquePtr()); } - ID.AddInteger(NoReturn); - ID.AddInteger(CallConv); + ID.AddInteger(Info.getNoReturn()); + ID.AddInteger(Info.getRegParm()); + ID.AddInteger(Info.getCC()); } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(), - getNumExceptions(), exception_begin(), getNoReturnAttr(), - getCallConv()); + getNumExceptions(), exception_begin(), + getExtInfo()); } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID, diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 0c4896d..4cf0922 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -282,7 +282,8 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += ")"; - switch(T->getCallConv()) { + FunctionType::ExtInfo Info = T->getExtInfo(); + switch(Info.getCC()) { case CC_Default: default: break; case CC_C: @@ -295,9 +296,11 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += " __attribute__((fastcall))"; break; } - if (T->getNoReturnAttr()) + if (Info.getNoReturn()) S += " __attribute__((noreturn))"; - + if (Info.getRegParm()) + S += " __attribute__((regparm (" + + llvm::utostr_32(Info.getRegParm()) + ")))"; if (T->hasExceptionSpec()) { S += " throw("; @@ -564,12 +567,20 @@ void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, S = MyString + ' ' + S; } -void TypePrinter::PrintTypename(const TypenameType *T, std::string &S) { +void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S) { std::string MyString; { llvm::raw_string_ostream OS(MyString); - OS << "typename "; + switch (T->getKeyword()) { + case ETK_None: break; + case ETK_Typename: OS << "typename "; break; + case ETK_Class: OS << "class "; break; + case ETK_Struct: OS << "struct "; break; + case ETK_Union: OS << "union "; break; + case ETK_Enum: OS << "enum "; break; + } + T->getQualifier()->print(OS, Policy); if (const IdentifierInfo *Ident = T->getIdentifier()) @@ -819,4 +830,3 @@ void QualType::getAsStringInternal(std::string &S, TypePrinter Printer(Policy); Printer.Print(*this, S); } - diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 5640c4a..06d8aec 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -54,8 +54,12 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { } CFG *AnalysisContext::getCFG() { - if (!cfg) + if (!builtCFG) { cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges); + // Even when the cfg is not successfully built, we don't + // want to try building it again. + builtCFG = true; + } return cfg; } @@ -126,9 +130,9 @@ LocationContextManager::getLocationContext(AnalysisContext *ctx, llvm::FoldingSetNodeID ID; LOC::Profile(ID, ctx, parent, d); void *InsertPos; - + LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); - + if (!L) { L = new LOC(ctx, parent, d); Contexts.InsertNode(L, InsertPos); @@ -144,7 +148,7 @@ LocationContextManager::getStackFrame(AnalysisContext *ctx, llvm::FoldingSetNodeID ID; StackFrameContext::Profile(ID, ctx, parent, s, blk, idx); void *InsertPos; - StackFrameContext *L = + StackFrameContext *L = cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); if (!L) { L = new StackFrameContext(ctx, parent, s, blk, idx); @@ -253,7 +257,7 @@ public: IgnoredContexts.insert(BR->getBlockDecl()); Visit(BR->getBlockDecl()->getBody()); } -}; +}; } // end anonymous namespace typedef BumpVector<const VarDecl*> DeclVec; @@ -263,16 +267,16 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD, llvm::BumpPtrAllocator &A) { if (Vec) return (DeclVec*) Vec; - + BumpVectorContext BC(A); DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>(); new (BV) DeclVec(BC, 10); - + // Find the referenced variables. FindBlockDeclRefExprsVals F(*BV, BC); F.Visit(BD->getBody()); - - Vec = BV; + + Vec = BV; return BV; } @@ -281,7 +285,7 @@ std::pair<AnalysisContext::referenced_decls_iterator, AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) { if (!ReferencedBlockVars) ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>(); - + DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A); return std::make_pair(V->begin(), V->end()); } @@ -310,12 +314,12 @@ LocationContextManager::~LocationContextManager() { void LocationContextManager::clear() { for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(), - E = Contexts.end(); I != E; ) { + E = Contexts.end(); I != E; ) { LocationContext *LC = &*I; ++I; delete LC; } - + Contexts.clear(); } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index a4a021f..f94f6b3 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -571,7 +571,7 @@ static bool CanThrow(Expr *E) { CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { // If this is a call to a no-return function, this stops the block here. bool NoReturn = false; - if (C->getCallee()->getType().getNoReturnAttr()) { + if (getFunctionExtInfo(*C->getCallee()->getType()).getNoReturn()) { NoReturn = true; } diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 46acc8a..c38aae3 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -75,7 +75,7 @@ static OptionalAmount ParseAmount(const char *&Beg, const char *E) { char c = *I; if (c >= '0' && c <= '9') { hasDigits = true; - accumulator += (accumulator * 10) + (c - '0'); + accumulator = (accumulator * 10) + (c - '0'); continue; } diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index f7ec873..2b7fcd0 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Parse/ParseDiagnostic.h" @@ -124,10 +125,20 @@ const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) { return 0; } -bool Diagnostic::isBuiltinSFINAEDiag(unsigned DiagID) { - if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) - return Info->SFINAE && Info->Class == CLASS_ERROR; - return false; +Diagnostic::SFINAEResponse +Diagnostic::getDiagnosticSFINAEResponse(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) { + if (!Info->SFINAE) + return SFINAE_Report; + + if (Info->Class == CLASS_ERROR) + return SFINAE_SubstitutionFailure; + + // Suppress notes, warnings, and extensions; + return SFINAE_Suppress; + } + + return SFINAE_Report; } /// getDiagClass - Return the class field of the diagnostic. @@ -222,6 +233,8 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { ArgToStringFn = DummyArgToStringFn; ArgToStringCookie = 0; + DelayedDiagID = 0; + // Set all mappings to 'unset'. DiagMappings BlankDiags(diag::DIAG_UPPER_LIMIT/2, 0); DiagMappingsStack.push_back(BlankDiags); @@ -289,6 +302,23 @@ const char *Diagnostic::getDescription(unsigned DiagID) const { return CustomDiagInfo->getDescription(DiagID); } +void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1, + llvm::StringRef Arg2) { + if (DelayedDiagID) + return; + + DelayedDiagID = DiagID; + DelayedDiagArg1 = Arg1.str(); + DelayedDiagArg2 = Arg2.str(); +} + +void Diagnostic::ReportDelayed() { + Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2; + DelayedDiagID = 0; + DelayedDiagArg1.clear(); + DelayedDiagArg2.clear(); +} + /// getDiagnosticLevel - Based on the way the client configured the Diagnostic /// object, classify the specified diagnostic ID into a Level, consumable by /// the DiagnosticClient. @@ -532,6 +562,35 @@ bool Diagnostic::ProcessDiag() { return true; } +bool DiagnosticBuilder::Emit() { + // If DiagObj is null, then its soul was stolen by the copy ctor + // or the user called Emit(). + if (DiagObj == 0) return false; + + // When emitting diagnostics, we set the final argument count into + // the Diagnostic object. + DiagObj->NumDiagArgs = NumArgs; + DiagObj->NumDiagRanges = NumRanges; + DiagObj->NumFixItHints = NumFixItHints; + + // Process the diagnostic, sending the accumulated information to the + // DiagnosticClient. + bool Emitted = DiagObj->ProcessDiag(); + + // Clear out the current diagnostic object. + unsigned DiagID = DiagObj->CurDiagID; + DiagObj->Clear(); + + // If there was a delayed diagnostic, emit it now. + if (DiagObj->DelayedDiagID && DiagObj->DelayedDiagID != DiagID) + DiagObj->ReportDelayed(); + + // This diagnostic is dead. + DiagObj = 0; + + return Emitted; +} + DiagnosticClient::~DiagnosticClient() {} @@ -937,9 +996,9 @@ StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I) Ranges.push_back(Info.getRange(I)); - FixIts.reserve(Info.getNumCodeModificationHints()); - for (unsigned I = 0, N = Info.getNumCodeModificationHints(); I != N; ++I) - FixIts.push_back(Info.getCodeModificationHint(I)); + FixIts.reserve(Info.getNumFixItHints()); + for (unsigned I = 0, N = Info.getNumFixItHints(); I != N; ++I) + FixIts.push_back(Info.getFixItHint(I)); } StoredDiagnostic::~StoredDiagnostic() { } @@ -1172,7 +1231,7 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM, return Diag; } - CodeModificationHint Hint; + FixItHint Hint; Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd); Hint.InsertionLoc = InsertionLoc; Hint.CodeToInsert.assign(Memory, Memory + InsertLen); @@ -1188,3 +1247,13 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM, /// DiagnosticClient should be included in the number of diagnostics /// reported by Diagnostic. bool DiagnosticClient::IncludeInDiagnosticCounts() const { return true; } + +PartialDiagnostic::StorageAllocator::StorageAllocator() { + for (unsigned I = 0; I != NumCached; ++I) + FreeList[I] = Cached + I; + NumFreeListEntries = NumCached; +} + +PartialDiagnostic::StorageAllocator::~StorageAllocator() { + assert(NumFreeListEntries == NumCached && "A partial is on the lamb"); +} diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 6def967..27cb9be 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -89,16 +89,26 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart()); for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) Ptr[i] = FillStr[i % FillStr.size()]; - Diag.Report(diag::err_cannot_open_file) - << Entry->getName() << ErrorStr; + + if (Diag.isDiagnosticInFlight()) + Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, + Entry->getName(), ErrorStr); + else + Diag.Report(diag::err_cannot_open_file) + << Entry->getName() << ErrorStr; + Buffer.setInt(true); } else if (FileInfo.st_size != Entry->getSize() || - FileInfo.st_mtime != Entry->getModificationTime() || - FileInfo.st_ino != Entry->getInode()) { + FileInfo.st_mtime != Entry->getModificationTime()) { // Check that the file's size, modification time, and inode are // the same as in the file entry (which may have come from a // stat cache). - Diag.Report(diag::err_file_modified) << Entry->getName(); + if (Diag.isDiagnosticInFlight()) + Diag.SetDelayedDiagnostic(diag::err_file_modified, + Entry->getName()); + else + Diag.Report(diag::err_file_modified) << Entry->getName(); + Buffer.setInt(true); } } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 8f472b3..e3d9ed3 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -292,6 +292,7 @@ protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { // PS3 PPU defines. + Builder.defineMacro("__PPC__"); Builder.defineMacro("__PPU__"); Builder.defineMacro("__CELLOS_LV2__"); Builder.defineMacro("__ELF__"); diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp index e95a86b..b92f2e7 100644 --- a/lib/Checker/AdjustedReturnValueChecker.cpp +++ b/lib/Checker/AdjustedReturnValueChecker.cpp @@ -14,11 +14,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/ADT/SmallString.h" using namespace clang; diff --git a/lib/Checker/AggExprVisitor.cpp b/lib/Checker/AggExprVisitor.cpp new file mode 100644 index 0000000..343afec --- /dev/null +++ b/lib/Checker/AggExprVisitor.cpp @@ -0,0 +1,55 @@ +//=-- AggExprVisitor.cpp - evaluating expressions of C++ class type -*- 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 AggExprVisitor class, which contains lots of boiler +// plate code for evaluating expressions of C++ class type. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/AST/StmtVisitor.h" + +using namespace clang; + +namespace { +class AggExprVisitor : public StmtVisitor<AggExprVisitor> { + SVal DestPtr; + ExplodedNode *Pred; + ExplodedNodeSet &DstSet; + GRExprEngine &Eng; + +public: + AggExprVisitor(SVal dest, ExplodedNode *N, ExplodedNodeSet &dst, + GRExprEngine &eng) + : DestPtr(dest), Pred(N), DstSet(dst), Eng(eng) {} + + void VisitCastExpr(CastExpr *E); + void VisitCXXConstructExpr(CXXConstructExpr *E); +}; +} + +void AggExprVisitor::VisitCastExpr(CastExpr *E) { + switch (E->getCastKind()) { + default: + assert(0 && "Unhandled cast kind"); + case CastExpr::CK_NoOp: + case CastExpr::CK_ConstructorConversion: + Visit(E->getSubExpr()); + break; + } +} + +void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) { + Eng.VisitCXXConstructExpr(E, DestPtr, Pred, DstSet); +} + +void GRExprEngine::VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + AggExprVisitor(Dest, Pred, Dst, *this).Visit(const_cast<Expr *>(E)); +} diff --git a/lib/Checker/ArrayBoundChecker.cpp b/lib/Checker/ArrayBoundChecker.cpp index 74fb06f..746b3f9 100644 --- a/lib/Checker/ArrayBoundChecker.cpp +++ b/lib/Checker/ArrayBoundChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" using namespace clang; diff --git a/lib/Checker/AttrNonNullChecker.cpp b/lib/Checker/AttrNonNullChecker.cpp index 83dc13e..309a74c 100644 --- a/lib/Checker/AttrNonNullChecker.cpp +++ b/lib/Checker/AttrNonNullChecker.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp index d6c09a2..810d0fb 100644 --- a/lib/Checker/BasicObjCFoundationChecks.cpp +++ b/lib/Checker/BasicObjCFoundationChecks.cpp @@ -19,9 +19,8 @@ #include "clang/Checker/PathSensitive/GRSimpleAPICheck.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/MemRegion.h" -#include "clang/Checker/BugReporter/PathDiagnostic.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/Checkers/LocalCheckers.h" #include "clang/AST/DeclObjC.h" diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp index 7272b34..12e61af 100644 --- a/lib/Checker/BugReporter.cpp +++ b/lib/Checker/BugReporter.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/AST/ASTContext.h" #include "clang/Analysis/CFG.h" @@ -1139,12 +1140,9 @@ void EdgeBuilder::addContext(const Stmt *S) { static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N) { - - EdgeBuilder EB(PD, PDB); - const ExplodedNode* NextNode = N->pred_empty() - ? NULL : *(N->pred_begin()); + const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); while (NextNode) { N = NextNode; NextNode = GetPredecessorNode(N); diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp index 1d6994b..06cee5b 100644 --- a/lib/Checker/BugReporterVisitors.cpp +++ b/lib/Checker/BugReporterVisitors.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/Checker/BugReporter/BugReporter.h" #include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/PathSensitive/ExplodedGraph.h" #include "clang/Checker/PathSensitive/GRState.h" using namespace clang; diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp index 9a76f6a..3c4a27c 100644 --- a/lib/Checker/CFRefCount.cpp +++ b/lib/Checker/CFRefCount.cpp @@ -16,8 +16,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/BugReporter/PathDiagnostic.h" #include "clang/Checker/Checkers/LocalCheckers.h" #include "clang/Checker/DomainSpecific/CocoaConventions.h" diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index c5bd2eb..dec375e 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangChecker AdjustedReturnValueChecker.cpp + AggExprVisitor.cpp ArrayBoundChecker.cpp AttrNonNullChecker.cpp BasicConstraintManager.cpp @@ -11,16 +12,16 @@ add_clang_library(clangChecker BugReporter.cpp BugReporterVisitors.cpp BuiltinFunctionChecker.cpp - CFRefCount.cpp CallAndMessageChecker.cpp CallInliner.cpp CastToStructChecker.cpp + CFRefCount.cpp CheckDeadStores.cpp + Checker.cpp CheckObjCDealloc.cpp CheckObjCInstMethSignature.cpp CheckSecuritySyntaxOnly.cpp CheckSizeofPointer.cpp - Checker.cpp CocoaConventions.cpp DereferenceChecker.cpp DivZeroChecker.cpp @@ -38,11 +39,11 @@ add_clang_library(clangChecker MallocChecker.cpp ManagerRegistry.cpp MemRegion.cpp + NoReturnFunctionChecker.cpp NSAutoreleasePoolChecker.cpp NSErrorChecker.cpp - NoReturnFunctionChecker.cpp - OSAtomicChecker.cpp ObjCUnusedIVarsChecker.cpp + OSAtomicChecker.cpp PathDiagnostic.cpp PointerArithChecker.cpp PointerSubChecker.cpp @@ -52,18 +53,18 @@ add_clang_library(clangChecker ReturnPointerRangeChecker.cpp ReturnStackAddressChecker.cpp ReturnUndefChecker.cpp - SVals.cpp - SValuator.cpp SimpleConstraintManager.cpp SimpleSValuator.cpp Store.cpp + SVals.cpp + SValuator.cpp SymbolManager.cpp UndefBranchChecker.cpp UndefCapturedBlockVarChecker.cpp - UndefResultChecker.cpp UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp + UndefResultChecker.cpp UnixAPIChecker.cpp - VLASizeChecker.cpp ValueManager.cpp + VLASizeChecker.cpp ) diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp index 32cf753..dd1856c9 100644 --- a/lib/Checker/CallAndMessageChecker.cpp +++ b/lib/Checker/CallAndMessageChecker.cpp @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// +#include "GRExprEngineInternalChecks.h" +#include "clang/AST/ParentMap.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "clang/AST/ParentMap.h" -#include "GRExprEngineInternalChecks.h" using namespace clang; diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp index bef5bc2..2c16f89 100644 --- a/lib/Checker/CastToStructChecker.cpp +++ b/lib/Checker/CastToStructChecker.cpp @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp index 923baf5..efbce61 100644 --- a/lib/Checker/CheckSecuritySyntaxOnly.cpp +++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp @@ -36,7 +36,7 @@ class WalkAST : public StmtVisitor<WalkAST> { IdentifierInfo *II_random; enum { num_setids = 6 }; IdentifierInfo *II_setid[num_setids]; - + const bool CheckRand; public: @@ -214,8 +214,8 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS; llvm::SmallVector<SourceRange, 2> ranges; - std::string sbuf; - llvm::raw_string_ostream os(sbuf); + llvm::SmallString<256> sbuf; + llvm::raw_svector_ostream os(sbuf); os << "Variable '" << drCond->getDecl()->getNameAsCString() << "' with floating point type '" << drCond->getType().getAsString() @@ -315,7 +315,7 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType()); if(!FPT) return; - + // Verify that the funcion takes a single argument. if (FPT->getNumArgs() != 1) return; @@ -328,17 +328,16 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { // Verify that the argument is a 'char*'. if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy) return; - + // Issue a waring. SourceRange R = CE->getCallee()->getSourceRange(); BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'", "Security", "Call to function 'mktemp' is insecure as it always " - "creates or uses insecure temporary file", + "creates or uses insecure temporary file. Use 'mkstemp' instead", CE->getLocStart(), &R, 1); } - //===----------------------------------------------------------------------===// // Check: Linear congruent random number generators should not be used // Originally: <rdar://problem/63371000> @@ -386,20 +385,18 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { return; // Issue a warning. - std::string buf1; - llvm::raw_string_ostream os1(buf1); + llvm::SmallString<256> buf1; + llvm::raw_svector_ostream os1(buf1); os1 << "'" << FD->getNameAsString() << "' is a poor random number generator"; - std::string buf2; - llvm::raw_string_ostream os2(buf2); + llvm::SmallString<256> buf2; + llvm::raw_svector_ostream os2(buf2); os2 << "Function '" << FD->getNameAsString() << "' is obsolete because it implements a poor random number generator." << " Use 'arc4random' instead"; SourceRange R = CE->getCallee()->getSourceRange(); - - BR.EmitBasicReport(os1.str(), "Security", os2.str(), - CE->getLocStart(), &R, 1); + BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1); } //===----------------------------------------------------------------------===// @@ -425,8 +422,7 @@ void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) { "Security", "The 'random' function produces a sequence of values that " "an adversary may be able to predict. Use 'arc4random' " - "instead", - CE->getLocStart(), &R, 1); + "instead", CE->getLocStart(), &R, 1); } //===----------------------------------------------------------------------===// @@ -474,22 +470,20 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { return; // Issue a warning. - std::string buf1; - llvm::raw_string_ostream os1(buf1); + llvm::SmallString<256> buf1; + llvm::raw_svector_ostream os1(buf1); os1 << "Return value is not checked in call to '" << FD->getNameAsString() << "'"; - std::string buf2; - llvm::raw_string_ostream os2(buf2); + llvm::SmallString<256> buf2; + llvm::raw_svector_ostream os2(buf2); os2 << "The return value from the call to '" << FD->getNameAsString() << "' is not checked. If an error occurs in '" << FD->getNameAsString() << "', the following code may execute with unexpected privileges"; SourceRange R = CE->getCallee()->getSourceRange(); - - BR.EmitBasicReport(os1.str(), "Security", os2.str(), - CE->getLocStart(), &R, 1); + BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1); } //===----------------------------------------------------------------------===// diff --git a/lib/Checker/DereferenceChecker.cpp b/lib/Checker/DereferenceChecker.cpp index 0cbc408..af74c79 100644 --- a/lib/Checker/DereferenceChecker.cpp +++ b/lib/Checker/DereferenceChecker.cpp @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// +#include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/Checkers/DereferenceChecker.h" #include "clang/Checker/PathSensitive/Checker.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "GRExprEngineInternalChecks.h" using namespace clang; @@ -29,9 +29,9 @@ 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); - + std::pair<ExplodedNode * const*, ExplodedNode * const*> - getImplicitNodes() const { + getImplicitNodes() const { return std::make_pair(ImplicitNullDerefNodes.data(), ImplicitNullDerefNodes.data() + ImplicitNullDerefNodes.size()); @@ -59,7 +59,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, if (ExplodedNode *N = C.GenerateSink()) { if (!BT_undef) BT_undef = new BuiltinBug("Dereference of undefined pointer value"); - + EnhancedBugReport *report = new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N); report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, @@ -68,31 +68,32 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, } return; } - + DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l); - - // Check for null dereferences. + + // Check for null dereferences. if (!isa<Loc>(location)) return; - + const GRState *state = C.getState(); const GRState *notNullState, *nullState; llvm::tie(notNullState, nullState) = state->Assume(location); - + // The explicit NULL case. if (nullState) { - if (!notNullState) { + if (!notNullState) { // Generate an error node. ExplodedNode *N = C.GenerateSink(nullState); if (!N) return; - + // We know that 'location' cannot be non-null. This is what - // we call an "explicit" null dereference. + // we call an "explicit" null dereference. if (!BT_null) BT_null = new BuiltinBug("Dereference of null pointer"); - + llvm::SmallString<100> buf; + llvm::SmallVector<SourceRange, 2> Ranges; switch (S->getStmtClass()) { case Stmt::UnaryOperatorClass: { @@ -101,10 +102,26 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { llvm::raw_svector_ostream os(buf); - os << "Dereference of null pointer loaded from variable '" - << VD->getName() << '\''; + os << "Dereference of null pointer (loaded from variable '" + << VD->getName() << "')"; + Ranges.push_back(DR->getSourceRange()); } } + break; + } + case Stmt::MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(S); + if (M->isArrow()) + if (DeclRefExpr *DR = + dyn_cast<DeclRefExpr>(M->getBase()->IgnoreParenCasts())) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { + llvm::raw_svector_ostream os(buf); + os << "Field access results in a dereference of a null pointer " + "(loaded from variable '" << VD->getName() << "')"; + Ranges.push_back(M->getBase()->getSourceRange()); + } + } + break; } default: break; @@ -117,19 +134,23 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, bugreporter::GetDerefExpr(N)); - + + for (llvm::SmallVectorImpl<SourceRange>::iterator + I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) + report->addRange(*I); + C.EmitReport(report); return; } else { // Otherwise, we have the case where the location could either be // null or not-null. Record the error node as an "implicit" null - // dereference. + // dereference. if (ExplodedNode *N = C.GenerateSink(nullState)) ImplicitNullDerefNodes.push_back(N); } } - + // From this point forward, we know that the location is not null. C.addTransition(notNullState); } diff --git a/lib/Checker/DivZeroChecker.cpp b/lib/Checker/DivZeroChecker.cpp index e1346e1..e09a871 100644 --- a/lib/Checker/DivZeroChecker.cpp +++ b/lib/Checker/DivZeroChecker.cpp @@ -12,8 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp index 671cf89..cc71f85 100644 --- a/lib/Checker/Environment.cpp +++ b/lib/Checker/Environment.cpp @@ -10,9 +10,10 @@ // This file defined the Environment and EnvironmentManager classes. // //===----------------------------------------------------------------------===// + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" #include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "llvm/ADT/ImmutableMap.h" using namespace clang; diff --git a/lib/Checker/FixedAddressChecker.cpp b/lib/Checker/FixedAddressChecker.cpp index 04c17d6..4fce45b 100644 --- a/lib/Checker/FixedAddressChecker.cpp +++ b/lib/Checker/FixedAddressChecker.cpp @@ -13,8 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/GRBlockCounter.cpp b/lib/Checker/GRBlockCounter.cpp index 3fa3e1e..cd26060 100644 --- a/lib/Checker/GRBlockCounter.cpp +++ b/lib/Checker/GRBlockCounter.cpp @@ -18,7 +18,34 @@ using namespace clang; -typedef llvm::ImmutableMap<unsigned,unsigned> CountMap; +namespace { + +class CountKey { + const StackFrameContext *CallSite; + unsigned BlockID; + +public: + CountKey(const StackFrameContext *CS, unsigned ID) + : CallSite(CS), BlockID(ID) {} + + bool operator==(const CountKey &RHS) const { + return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID); + } + + bool operator<(const CountKey &RHS) const { + return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID) + : (CallSite < RHS.CallSite); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(CallSite); + ID.AddInteger(BlockID); + } +}; + +} + +typedef llvm::ImmutableMap<CountKey, unsigned> CountMap; static inline CountMap GetMap(void* D) { return CountMap(static_cast<CountMap::TreeTy*>(D)); @@ -28,9 +55,10 @@ static inline CountMap::Factory& GetFactory(void* F) { return *static_cast<CountMap::Factory*>(F); } -unsigned GRBlockCounter::getNumVisited(unsigned BlockID) const { +unsigned GRBlockCounter::getNumVisited(const StackFrameContext *CallSite, + unsigned BlockID) const { CountMap M = GetMap(Data); - CountMap::data_type* T = M.lookup(BlockID); + CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID)); return T ? *T : 0; } @@ -43,9 +71,12 @@ GRBlockCounter::Factory::~Factory() { } GRBlockCounter -GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, unsigned BlockID) { - return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), BlockID, - BC.getNumVisited(BlockID)+1).getRoot()); +GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, + const StackFrameContext *CallSite, + unsigned BlockID) { + return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), + CountKey(CallSite, BlockID), + BC.getNumVisited(CallSite, BlockID)+1).getRoot()); } GRBlockCounter diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index a9347d0..e4ef6b0 100644 --- a/lib/Checker/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -126,9 +126,9 @@ void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) { SubEngine.ProcessStmt(E, Builder); } -bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, +bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const ExplodedNode *Pred, GRBlockCounter BC) { - return SubEngine.ProcessBlockEntrance(Blk, State, BC); + return SubEngine.ProcessBlockEntrance(Blk, Pred, BC); } void GRCoreEngine::ProcessBranch(Stmt* Condition, Stmt* Terminator, @@ -256,7 +256,7 @@ void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { // FIXME: Should we allow ProcessBlockEntrance to also manipulate state? - if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter())) + if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter())) GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred); } @@ -265,7 +265,9 @@ void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L, // Increment the block counter. GRBlockCounter Counter = WList->getBlockCounter(); - Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID()); + Counter = BCounterFactory.IncrementCount(Counter, + Pred->getLocationContext()->getCurrentStackFrame(), + L.getBlock()->getBlockID()); WList->setBlockCounter(Counter); // Process the entrance of the block. diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 3ace552..bab8922 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -13,6 +13,8 @@ // //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/AnalysisManager.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/PathSensitive/GRExprEngineBuilders.h" #include "clang/Checker/PathSensitive/Checker.h" @@ -582,7 +584,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { switch (S->getStmtClass()) { // C++ stuff we don't support yet. - case Stmt::CXXMemberCallExprClass: case Stmt::CXXNamedCastExprClass: case Stmt::CXXStaticCastExprClass: case Stmt::CXXDynamicCastExprClass: @@ -671,6 +672,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } + case Stmt::CXXMemberCallExprClass: { + CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S); + VisitCXXMemberCallExpr(MCE, Pred, Dst); + break; + } + // FIXME: ChooseExpr is really a constant. We need to fix // the CFG do not model them as explicit control-flow. @@ -895,6 +902,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; } + case Stmt::ObjCIsaExprClass: + // FIXME: Do something more intelligent with 'x->isa = ...'. + // For now, just ignore the assignment. + return; + case Stmt::ObjCPropertyRefExprClass: case Stmt::ObjCImplicitSetterGetterRefExprClass: // FIXME: Property assignments are lvalues, but not really "locations". @@ -944,10 +956,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, // Block entrance. (Update counters). //===----------------------------------------------------------------------===// -bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*, +bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred, GRBlockCounter BC) { - return BC.getNumVisited(B->getBlockID()) < 3; + return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(), + B->getBlockID()) < 3; } //===----------------------------------------------------------------------===// @@ -1328,6 +1341,22 @@ void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { if (ReturnedExpr) { SVal RetVal = state->getSVal(ReturnedExpr); state = state->BindExpr(CE, RetVal); + // Clear the return expr GDM. + state = state->remove<ReturnExpr>(); + } + + // Bind the constructed object value to CXXConstructExpr. + if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { + const CXXThisRegion *ThisR = getCXXThisRegion(CCE->getConstructor(),LocCtx); + // We might not have 'this' region in the binding if we didn't inline + // the ctor call. + SVal ThisV = state->getSVal(ThisR); + loc::MemRegionVal *V = dyn_cast<loc::MemRegionVal>(&ThisV); + if (V) { + SVal ObjVal = state->getSVal(V->getRegion()); + assert(isa<nonloc::LazyCompoundVal>(ObjVal)); + state = state->BindExpr(CCE, ObjVal); + } } B.GenerateNode(state); @@ -2282,6 +2311,7 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, case CastExpr::CK_AnyPointerToObjCPointerCast: case CastExpr::CK_AnyPointerToBlockPointerCast: case CastExpr::CK_DerivedToBase: + case CastExpr::CK_UncheckedDerivedToBase: // Delegate to SValuator to process. for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { ExplodedNode* N = *I; @@ -2338,8 +2368,10 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet Tmp; if (InitEx) { - if (const CXXConstructExpr *E = dyn_cast<CXXConstructExpr>(InitEx)) { - VisitCXXConstructExpr(E, GetState(Pred)->getLValue(VD, + QualType InitTy = InitEx->getType(); + if (getContext().getLangOptions().CPlusPlus && InitTy->isRecordType()) { + // Delegate expressions of C++ record type evaluation to AggExprVisitor. + VisitAggExpr(InitEx, GetState(Pred)->getLValue(VD, Pred->getLocationContext()), Pred, Dst); return; } else if (VD->getType()->isReferenceType()) @@ -2908,7 +2940,8 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet Src; if (Expr *RetE = RS->getRetValue()) { - // Record the returned expression in the state. + // Record the returned expression in the state. It will be used in + // ProcessCallExit to bind the return value to the call expr. { static int Tag = 0; SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag); @@ -3137,6 +3170,10 @@ void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + if (E->isElidable()) { + VisitAggExpr(E->getArg(0), Dest, Pred, Dst); + return; + } const CXXConstructorDecl *CD = E->getConstructor(); assert(CD); @@ -3190,10 +3227,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, Pred->getLocationContext(), E, Builder->getBlock(), Builder->getIndex()); - Type *T = CD->getParent()->getTypeForDecl(); - QualType PT = getContext().getPointerType(QualType(T,0)); - const CXXThisRegion *ThisR = ValMgr.getRegionManager().getCXXThisRegion(PT, - SFC); + const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); CallEnter Loc(E, CD, Pred->getLocationContext()); for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), @@ -3206,6 +3240,91 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, Dst.Add(N); } } + +void GRExprEngine::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. + CallExpr::arg_iterator AB = const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(), + AE = const_cast<CXXMemberCallExpr*>(MCE)->arg_end(); + llvm::SmallVector<CallExprWLItem, 20> WorkList; + WorkList.reserve(AE - AB); + WorkList.push_back(CallExprWLItem(AB, Pred)); + ExplodedNodeSet ArgsEvaluated; + + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + ArgsEvaluated.insert(Item.N); + continue; + } + + ExplodedNodeSet Tmp; + const unsigned ParamIdx = Item.I - AB; + bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType(); + + if (VisitAsLvalue) + VisitLValue(*Item.I, Item.N, Tmp); + else + Visit(*Item.I, Item.N, Tmp); + + ++(Item.I); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); + } + // 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) { + if (ME->isArrow()) + Visit(ObjArgExpr, *I, AllArgsEvaluated); + else + VisitLValue(ObjArgExpr, *I, AllArgsEvaluated); + } + + const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); + assert(MD && "not a CXXMethodDecl?"); + + if (!MD->isThisDeclarationADefinition()) + // FIXME: conservative method call evaluation. + return; + + const StackFrameContext *SFC = AMgr.getStackFrame(MD, + Pred->getLocationContext(), + MCE, + Builder->getBlock(), + Builder->getIndex()); + const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); + CallEnter Loc(MCE, MD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), + E = AllArgsEvaluated.end(); I != E; ++I) { + // Set up 'this' region. + const GRState *state = GetState(*I); + state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); + ExplodedNode *N = Builder->generateNode(Loc, state, *I); + if (N) + Dst.Add(N); + } +} + +const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, + const StackFrameContext *SFC) { + Type *T = D->getParent()->getTypeForDecl(); + QualType PT = getContext().getPointerType(QualType(T,0)); + return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); +} + //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===// diff --git a/lib/Checker/GRState.cpp b/lib/Checker/GRState.cpp index 2defbcd..f68e10b 100644 --- a/lib/Checker/GRState.cpp +++ b/lib/Checker/GRState.cpp @@ -11,10 +11,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/Analysis/CFG.h" #include "clang/Checker/PathSensitive/GRStateTrait.h" #include "clang/Checker/PathSensitive/GRState.h" #include "clang/Checker/PathSensitive/GRTransferFuncs.h" -#include "llvm/ADT/SmallSet.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -227,6 +227,18 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){ return getPersistentState(NewSt); } +const GRState *GRStateManager::removeGDM(const GRState *state, void *Key) { + GRState::GenericDataMap OldM = state->getGDM(); + GRState::GenericDataMap NewM = GDMFactory.Remove(OldM, Key); + + if (NewM == OldM) + return state; + + GRState NewState = *state; + NewState.GDM = NewM; + return getPersistentState(NewState); +} + //===----------------------------------------------------------------------===// // Utility. //===----------------------------------------------------------------------===// diff --git a/lib/Checker/MacOSXAPIChecker.cpp b/lib/Checker/MacOSXAPIChecker.cpp index 9621e85..bcd96e7 100644 --- a/lib/Checker/MacOSXAPIChecker.cpp +++ b/lib/Checker/MacOSXAPIChecker.cpp @@ -17,7 +17,7 @@ #include "GRExprEngineInternalChecks.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRStateTrait.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Checker/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp index a08afc4..a22df30 100644 --- a/lib/Checker/MallocChecker.cpp +++ b/lib/Checker/MallocChecker.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineExperimentalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRState.h" #include "clang/Checker/PathSensitive/GRStateTrait.h" diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp index 9a26988..9f12ab6 100644 --- a/lib/Checker/MemRegion.cpp +++ b/lib/Checker/MemRegion.cpp @@ -13,10 +13,10 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/AnalysisContext.h" #include "clang/Checker/PathSensitive/MemRegion.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/Support/BumpVector.h" #include "clang/AST/CharUnits.h" -#include "clang/AST/StmtVisitor.h" #include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp index e428e2e..9130bfa 100644 --- a/lib/Checker/NSErrorChecker.cpp +++ b/lib/Checker/NSErrorChecker.cpp @@ -16,7 +16,7 @@ //===----------------------------------------------------------------------===// #include "clang/Checker/Checkers/LocalCheckers.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/Checkers/DereferenceChecker.h" #include "BasicObjCFoundationChecks.h" diff --git a/lib/Checker/NoReturnFunctionChecker.cpp b/lib/Checker/NoReturnFunctionChecker.cpp index 1455d87..12527e0 100644 --- a/lib/Checker/NoReturnFunctionChecker.cpp +++ b/lib/Checker/NoReturnFunctionChecker.cpp @@ -13,17 +13,17 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/Checker.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; namespace { -class NoReturnFunctionChecker : public Checker { +class NoReturnFunctionChecker : public CheckerVisitor<NoReturnFunctionChecker> { public: static void *getTag() { static int tag = 0; return &tag; } - virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); + void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); }; } @@ -32,48 +32,48 @@ void clang::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) { Eng.registerCheck(new NoReturnFunctionChecker()); } -bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C, - const CallExpr *CE) { +void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C, + const CallExpr *CE) { const GRState *state = C.getState(); const Expr *Callee = CE->getCallee(); - SVal L = state->getSVal(Callee); - const FunctionDecl *FD = L.getAsFunctionDecl(); - if (!FD) - return false; - bool BuildSinks = false; + bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn(); - if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>()) - BuildSinks = true; - else if (const IdentifierInfo *II = FD->getIdentifier()) { - // HACK: Some functions are not marked noreturn, and don't return. - // Here are a few hardwired ones. If this takes too long, we can - // potentially cache these results. - BuildSinks - = llvm::StringSwitch<bool>(llvm::StringRef(II->getName())) - .Case("exit", true) - .Case("panic", true) - .Case("error", true) - .Case("Assert", true) - // FIXME: This is just a wrapper around throwing an exception. - // Eventually inter-procedural analysis should handle this easily. - .Case("ziperr", true) - .Case("assfail", true) - .Case("db_error", true) - .Case("__assert", true) - .Case("__assert_rtn", true) - .Case("__assert_fail", true) - .Case("dtrace_assfail", true) - .Case("yy_fatal_error", true) - .Case("_XCAssertionFailureHandler", true) - .Case("_DTAssertionFailureHandler", true) - .Case("_TSAssertionFailureHandler", true) - .Default(false); + if (!BuildSinks) { + SVal L = state->getSVal(Callee); + const FunctionDecl *FD = L.getAsFunctionDecl(); + if (!FD) + return; + + if (FD->getAttr<AnalyzerNoReturnAttr>()) + BuildSinks = true; + else if (const IdentifierInfo *II = FD->getIdentifier()) { + // HACK: Some functions are not marked noreturn, and don't return. + // Here are a few hardwired ones. If this takes too long, we can + // potentially cache these results. + BuildSinks + = llvm::StringSwitch<bool>(llvm::StringRef(II->getName())) + .Case("exit", true) + .Case("panic", true) + .Case("error", true) + .Case("Assert", true) + // FIXME: This is just a wrapper around throwing an exception. + // Eventually inter-procedural analysis should handle this easily. + .Case("ziperr", true) + .Case("assfail", true) + .Case("db_error", true) + .Case("__assert", true) + .Case("__assert_rtn", true) + .Case("__assert_fail", true) + .Case("dtrace_assfail", true) + .Case("yy_fatal_error", true) + .Case("_XCAssertionFailureHandler", true) + .Case("_DTAssertionFailureHandler", true) + .Case("_TSAssertionFailureHandler", true) + .Default(false); + } } - - if (!BuildSinks) - return false; - C.GenerateSink(CE); - return true; + if (BuildSinks) + C.GenerateSink(CE); } diff --git a/lib/Checker/PathDiagnostic.cpp b/lib/Checker/PathDiagnostic.cpp index 97500d9..963923c 100644 --- a/lib/Checker/PathDiagnostic.cpp +++ b/lib/Checker/PathDiagnostic.cpp @@ -108,8 +108,8 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) P->addRange(Info.getRange(i)); - for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i) - P->addCodeModificationHint(Info.getCodeModificationHint(i)); + for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) + P->addFixItHint(Info.getFixItHint(i)); D->push_front(P); HandlePathDiagnostic(D); diff --git a/lib/Checker/PointerArithChecker.cpp b/lib/Checker/PointerArithChecker.cpp index 3d62d0c..ed60c42 100644 --- a/lib/Checker/PointerArithChecker.cpp +++ b/lib/Checker/PointerArithChecker.cpp @@ -12,8 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/PointerSubChecker.cpp b/lib/Checker/PointerSubChecker.cpp index acc848a..bc0fd24 100644 --- a/lib/Checker/PointerSubChecker.cpp +++ b/lib/Checker/PointerSubChecker.cpp @@ -13,8 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index c2b702a..c97da33 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -536,15 +536,15 @@ public: // First visit the cluster. static_cast<DERIVED*>(this)->VisitCluster(baseR, C->begin(), C->end()); - // Next, visit the region. - static_cast<DERIVED*>(this)->VisitRegion(baseR); + // Next, visit the base region. + static_cast<DERIVED*>(this)->VisitBaseRegion(baseR); } } public: void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C) {} void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E) {} - void VisitRegion(const MemRegion *baseR) {} + void VisitBaseRegion(const MemRegion *baseR) {} }; } @@ -580,7 +580,7 @@ public: Ex(ex), Count(count), IS(is) {} void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E); - void VisitRegion(const MemRegion *baseR); + void VisitBaseRegion(const MemRegion *baseR); private: void VisitBinding(SVal V); @@ -627,7 +627,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, } } -void InvalidateRegionsWorker::VisitRegion(const MemRegion *baseR) { +void InvalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { if (IS) { // Symbolic region? Mark that symbol touched by the invalidation. if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) @@ -787,9 +787,12 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, return ValMgr.makeIntVal(CAT->getSize(), false); } - // Clients can use ordinary variables as if they were arrays. These - // essentially are arrays of size 1. - return ValMgr.makeIntVal(1, false); + // Clients can reinterpret ordinary variables as arrays, possibly of + // another type. The width is rounded down to ensure that an access is + // entirely within bounds. + CharUnits VarSize = getContext().getTypeSizeInChars(T); + CharUnits EleSize = getContext().getTypeSizeInChars(EleTy); + return ValMgr.makeIntVal(VarSize / EleSize, false); } } @@ -963,7 +966,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B, Optional<SVal> RegionStoreManager::getBinding(RegionBindings B, const MemRegion *R) { - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return V; return getDefaultBinding(B, R); @@ -1044,7 +1047,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { } #endif - if (RTy->isStructureType()) + if (RTy->isStructureType() || RTy->isClassType()) return RetrieveStruct(store, R); // FIXME: Handle unions. @@ -1144,7 +1147,7 @@ SVal RegionStoreManager::RetrieveElement(Store store, const ElementRegion* R) { // Check if the region has a binding. RegionBindings B = GetRegionBindings(store); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return *V; const MemRegion* superR = R->getSuperRegion(); @@ -1175,7 +1178,7 @@ SVal RegionStoreManager::RetrieveElement(Store store, } // Check if the immediate super region has a direct binding. - if (Optional<SVal> V = getDirectBinding(B, superR)) { + if (const Optional<SVal> &V = getDirectBinding(B, superR)) { if (SymbolRef parentSym = V->getAsSymbol()) return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); @@ -1203,7 +1206,7 @@ SVal RegionStoreManager::RetrieveField(Store store, // Check if the region has a binding. RegionBindings B = GetRegionBindings(store); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return *V; QualType Ty = R->getValueType(getContext()); @@ -1278,13 +1281,13 @@ SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){ // Check if the region has a binding. RegionBindings B = GetRegionBindings(store); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return *V; const MemRegion *superR = R->getSuperRegion(); // Check if the super region has a default binding. - if (Optional<SVal> V = getDefaultBinding(B, superR)) { + if (const Optional<SVal> &V = getDefaultBinding(B, superR)) { if (SymbolRef parentSym = V->getAsSymbol()) return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); @@ -1300,7 +1303,7 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) { // Check if the region has a binding. RegionBindings B = GetRegionBindings(store); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return *V; // Lazily derive a value for the VarRegion. @@ -1313,8 +1316,23 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) { return ValMgr.getRegionValueSymbolVal(R); if (isa<GlobalsSpaceRegion>(MS)) { - if (VD->isFileVarDecl()) + if (VD->isFileVarDecl()) { + // Is 'VD' declared constant? If so, retrieve the constant value. + QualType CT = Ctx.getCanonicalType(T); + if (CT.isConstQualified()) { + const Expr *Init = VD->getInit(); + // Do the null check first, as we want to call 'IgnoreParenCasts'. + if (Init) + if (const IntegerLiteral *IL = + dyn_cast<IntegerLiteral>(Init->IgnoreParenCasts())) { + const nonloc::ConcreteInt &V = ValMgr.makeIntVal(IL); + return ValMgr.getSValuator().EvalCast(V, Init->getType(), + IL->getType()); + } + } + return ValMgr.getRegionValueSymbolVal(R); + } if (T->isIntegerType()) return ValMgr.makeIntVal(0, T); @@ -1337,8 +1355,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { QualType T = R->getValueType(getContext()); - assert(T->isStructureType()); - assert(T->getAsStructureType()->getDecl()->isDefinition()); + assert(T->isStructureType() || T->isClassType()); return ValMgr.makeLazyCompoundVal(store, R); } @@ -1692,8 +1709,8 @@ public: // Called by ClusterAnalysis. void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C); void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E); - void VisitRegion(const MemRegion *baseR); + void VisitBindingKey(BindingKey K); bool UpdatePostponed(); void VisitBinding(SVal V); }; @@ -1730,11 +1747,8 @@ void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E) { - for ( ; I != E; ++I) { - const MemRegion *R = I->getRegion(); - if (R != baseR) - VisitRegion(R); - } + for ( ; I != E; ++I) + VisitBindingKey(*I); } void RemoveDeadBindingsWorker::VisitBinding(SVal V) { @@ -1762,34 +1776,36 @@ void RemoveDeadBindingsWorker::VisitBinding(SVal V) { SymReaper.markLive(*SI); } -void RemoveDeadBindingsWorker::VisitRegion(const MemRegion *R) { +void RemoveDeadBindingsWorker::VisitBindingKey(BindingKey K) { + const MemRegion *R = K.getRegion(); + // Mark this region "live" by adding it to the worklist. This will cause // use to visit all regions in the cluster (if we haven't visited them // already). - AddToWorkList(R); - - // Mark the symbol for any live SymbolicRegion as "live". This means we - // should continue to track that symbol. - if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) - SymReaper.markLive(SymR->getSymbol()); + if (AddToWorkList(R)) { + // Mark the symbol for any live SymbolicRegion as "live". This means we + // should continue to track that symbol. + if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) + SymReaper.markLive(SymR->getSymbol()); + + // For BlockDataRegions, enqueue the VarRegions for variables marked + // with __block (passed-by-reference). + // via BlockDeclRefExprs. + if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) { + for (BlockDataRegion::referenced_vars_iterator + RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end(); + RI != RE; ++RI) { + if ((*RI)->getDecl()->getAttr<BlocksAttr>()) + AddToWorkList(*RI); + } - // For BlockDataRegions, enqueue the VarRegions for variables marked - // with __block (passed-by-reference). - // via BlockDeclRefExprs. - if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) { - for (BlockDataRegion::referenced_vars_iterator - RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end(); - RI != RE; ++RI) { - if ((*RI)->getDecl()->getAttr<BlocksAttr>()) - AddToWorkList(*RI); + // No possible data bindings on a BlockDataRegion. + return; } - - // No possible data bindings on a BlockDataRegion. - return; } - // Get the data binding for R (if any). - if (Optional<SVal> V = RM.getBinding(B, R)) + // Visit the data binding for K. + if (const SVal *V = RM.Lookup(B, K)) VisitBinding(*V); } diff --git a/lib/Checker/ReturnPointerRangeChecker.cpp b/lib/Checker/ReturnPointerRangeChecker.cpp index 949ded5..14edf56 100644 --- a/lib/Checker/ReturnPointerRangeChecker.cpp +++ b/lib/Checker/ReturnPointerRangeChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" using namespace clang; diff --git a/lib/Checker/ReturnStackAddressChecker.cpp b/lib/Checker/ReturnStackAddressChecker.cpp index 9cbabba..35b1cde 100644 --- a/lib/Checker/ReturnStackAddressChecker.cpp +++ b/lib/Checker/ReturnStackAddressChecker.cpp @@ -14,8 +14,8 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Checker/ReturnUndefChecker.cpp b/lib/Checker/ReturnUndefChecker.cpp index ee25988..52a0b30 100644 --- a/lib/Checker/ReturnUndefChecker.cpp +++ b/lib/Checker/ReturnUndefChecker.cpp @@ -14,10 +14,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "llvm/ADT/SmallString.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" using namespace clang; diff --git a/lib/Checker/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp index 65a46e3..f3a803c 100644 --- a/lib/Checker/SymbolManager.cpp +++ b/lib/Checker/SymbolManager.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "clang/Checker/PathSensitive/SymbolManager.h" +#include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Checker/PathSensitive/MemRegion.h" -#include "clang/Analysis/AnalysisContext.h" #include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Checker/UndefBranchChecker.cpp b/lib/Checker/UndefBranchChecker.cpp index e047b18..9088345 100644 --- a/lib/Checker/UndefBranchChecker.cpp +++ b/lib/Checker/UndefBranchChecker.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/Checker.h" using namespace clang; diff --git a/lib/Checker/UndefCapturedBlockVarChecker.cpp b/lib/Checker/UndefCapturedBlockVarChecker.cpp index a8d7284..b1010c9 100644 --- a/lib/Checker/UndefCapturedBlockVarChecker.cpp +++ b/lib/Checker/UndefCapturedBlockVarChecker.cpp @@ -14,7 +14,7 @@ #include "GRExprEngineInternalChecks.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Checker/UndefResultChecker.cpp b/lib/Checker/UndefResultChecker.cpp index fb2283a..8b07aed 100644 --- a/lib/Checker/UndefResultChecker.cpp +++ b/lib/Checker/UndefResultChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" using namespace clang; diff --git a/lib/Checker/UndefinedArraySubscriptChecker.cpp b/lib/Checker/UndefinedArraySubscriptChecker.cpp index a2792ad..148629e 100644 --- a/lib/Checker/UndefinedArraySubscriptChecker.cpp +++ b/lib/Checker/UndefinedArraySubscriptChecker.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/UndefinedAssignmentChecker.cpp b/lib/Checker/UndefinedAssignmentChecker.cpp index 7c33c1d..6cef60e 100644 --- a/lib/Checker/UndefinedAssignmentChecker.cpp +++ b/lib/Checker/UndefinedAssignmentChecker.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" using namespace clang; @@ -53,27 +53,43 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, if (!N) return; + const char *str = "Assigned value is garbage or undefined"; + if (!BT) - BT = new BuiltinBug("Assigned value is garbage or undefined"); + BT = new BuiltinBug(str); // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); + const Expr *ex = 0; - if (AssignE) { - const Expr *ex = 0; + while (AssignE) { + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(AssignE)) { + if (B->isCompoundAssignmentOp()) { + const GRState *state = C.getState(); + if (state->getSVal(B->getLHS()).isUndef()) { + str = "The left expression of the compound assignment is an " + "uninitialized value. The computed value will also be garbage"; + ex = B->getLHS(); + break; + } + } - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(AssignE)) ex = B->getRHS(); - else if (const DeclStmt *DS = dyn_cast<DeclStmt>(AssignE)) { + break; + } + + if (const DeclStmt *DS = dyn_cast<DeclStmt>(AssignE)) { const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl()); ex = VD->getInit(); } - if (ex) { - R->addRange(ex->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex); - } + + break; } + EnhancedBugReport *R = new EnhancedBugReport(*BT, str, N); + if (ex) { + R->addRange(ex->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex); + } C.EmitReport(R); -} +} diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp index 7ff817a..d75e5d2 100644 --- a/lib/Checker/UnixAPIChecker.cpp +++ b/lib/Checker/UnixAPIChecker.cpp @@ -12,11 +12,10 @@ // //===----------------------------------------------------------------------===// +#include "GRExprEngineInternalChecks.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/BugReporter/BugType.h" #include "llvm/ADT/StringSwitch.h" -#include "GRExprEngineInternalChecks.h" #include <fcntl.h> using namespace clang; diff --git a/lib/Checker/VLASizeChecker.cpp b/lib/Checker/VLASizeChecker.cpp index 51ad1e2..cea9d19 100644 --- a/lib/Checker/VLASizeChecker.cpp +++ b/lib/Checker/VLASizeChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" using namespace clang; diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index c10a401..5097341 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -17,6 +17,7 @@ #include "CodeGenModule.h" #include "clang/AST/DeclObjC.h" #include "llvm/Module.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/Target/TargetData.h" #include <algorithm> @@ -192,7 +193,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { CallArgList Args; CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, Args, - CC_Default, false); + FunctionType::ExtInfo()); if (CGM.ReturnTypeUsesSret(FnInfo)) flags |= BLOCK_USE_STRET; } @@ -472,8 +473,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, QualType ResultType = FuncTy->getResultType(); const CGFunctionInfo &FnInfo = - CGM.getTypes().getFunctionInfo(ResultType, Args, FuncTy->getCallConv(), - FuncTy->getNoReturnAttr()); + CGM.getTypes().getFunctionInfo(ResultType, Args, + FuncTy->getExtInfo()); // Cast the function pointer to the right type. const llvm::Type *BlockFTy = @@ -678,8 +679,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, const FunctionType *BlockFunctionType = BExpr->getFunctionType(); QualType ResultType; - CallingConv CC = BlockFunctionType->getCallConv(); - bool NoReturn = BlockFunctionType->getNoReturnAttr(); + FunctionType::ExtInfo EInfo = getFunctionExtInfo(*BlockFunctionType); bool IsVariadic; if (const FunctionProtoType *FTy = dyn_cast<FunctionProtoType>(BlockFunctionType)) { @@ -718,7 +718,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, Args.push_back(std::make_pair(*i, (*i)->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(ResultType, Args, CC, NoReturn); + CGM.getTypes().getFunctionInfo(ResultType, Args, EInfo); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic); @@ -843,7 +843,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); + CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo()); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. @@ -924,7 +924,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); + CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo()); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. @@ -1008,7 +1008,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); + CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo()); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); @@ -1071,7 +1071,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); + CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo()); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index e91319f..efee0e3 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -17,7 +17,6 @@ #include "CodeGenTypes.h" #include "clang/AST/Type.h" #include "llvm/Module.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "clang/Basic/TargetInfo.h" #include "clang/AST/CharUnits.h" diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 419ed73..a9b0b64 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -81,10 +81,6 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF, Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)), CGF.EmitScalarExpr(E->getArg(1)) }; Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2); - - if (Id == Intrinsic::atomic_load_nand) - Result = CGF.Builder.CreateNot(Result); - return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Args[1])); } @@ -550,12 +546,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_fetch_and_xor_8: case Builtin::BI__sync_fetch_and_xor_16: return EmitBinaryAtomic(*this, Intrinsic::atomic_load_xor, E); - case Builtin::BI__sync_fetch_and_nand_1: - case Builtin::BI__sync_fetch_and_nand_2: - case Builtin::BI__sync_fetch_and_nand_4: - case Builtin::BI__sync_fetch_and_nand_8: - case Builtin::BI__sync_fetch_and_nand_16: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_nand, E); // Clang extensions: not overloaded yet. case Builtin::BI__sync_fetch_and_min: @@ -602,13 +592,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_xor_and_fetch_16: return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_xor, E, llvm::Instruction::Xor); - case Builtin::BI__sync_nand_and_fetch_1: - case Builtin::BI__sync_nand_and_fetch_2: - case Builtin::BI__sync_nand_and_fetch_4: - case Builtin::BI__sync_nand_and_fetch_8: - case Builtin::BI__sync_nand_and_fetch_16: - return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_nand, E, - llvm::Instruction::And); case Builtin::BI__sync_val_compare_and_swap_1: case Builtin::BI__sync_val_compare_and_swap_2: diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index b88001c..93a182f 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -297,311 +297,6 @@ void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name, getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer()); } -llvm::Constant * -CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, - bool Extern, - const ThunkAdjustment &ThisAdjustment) { - return GenerateCovariantThunk(Fn, GD, Extern, - CovariantThunkAdjustment(ThisAdjustment, - ThunkAdjustment())); -} - -llvm::Value * -CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, - const ThunkAdjustment &Adjustment) { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - - const llvm::Type *OrigTy = V->getType(); - if (Adjustment.NonVirtual) { - // Do the non-virtual adjustment - V = Builder.CreateBitCast(V, Int8PtrTy); - V = Builder.CreateConstInBoundsGEP1_64(V, Adjustment.NonVirtual); - V = Builder.CreateBitCast(V, OrigTy); - } - - if (!Adjustment.Virtual) - return V; - - assert(Adjustment.Virtual % (LLVMPointerWidth / 8) == 0 && - "vtable entry unaligned"); - - // Do the virtual this adjustment - const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); - const llvm::Type *PtrDiffPtrTy = PtrDiffTy->getPointerTo(); - - llvm::Value *ThisVal = Builder.CreateBitCast(V, Int8PtrTy); - V = Builder.CreateBitCast(V, PtrDiffPtrTy->getPointerTo()); - V = Builder.CreateLoad(V, "vtable"); - - llvm::Value *VTablePtr = V; - uint64_t VirtualAdjustment = Adjustment.Virtual / (LLVMPointerWidth / 8); - V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment); - V = Builder.CreateLoad(V); - V = Builder.CreateGEP(ThisVal, V); - - return Builder.CreateBitCast(V, OrigTy); -} - -llvm::Constant * -CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, - GlobalDecl GD, bool Extern, - const CovariantThunkAdjustment &Adjustment) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - QualType ResultType = FPT->getResultType(); - - FunctionArgList Args; - ImplicitParamDecl *ThisDecl = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, - MD->getThisType(getContext())); - Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); - for (FunctionDecl::param_const_iterator i = MD->param_begin(), - e = MD->param_end(); - i != e; ++i) { - ParmVarDecl *D = *i; - Args.push_back(std::make_pair(D, D->getType())); - } - IdentifierInfo *II - = &CGM.getContext().Idents.get("__thunk_named_foo_"); - FunctionDecl *FD = FunctionDecl::Create(getContext(), - getContext().getTranslationUnitDecl(), - SourceLocation(), II, ResultType, 0, - Extern - ? FunctionDecl::Extern - : FunctionDecl::Static, - false, true); - StartFunction(FD, ResultType, Fn, Args, SourceLocation()); - - // generate body - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); - - CallArgList CallArgs; - - bool ShouldAdjustReturnPointer = true; - QualType ArgType = MD->getThisType(getContext()); - llvm::Value *Arg = Builder.CreateLoad(LocalDeclMap[ThisDecl], "this"); - if (!Adjustment.ThisAdjustment.isEmpty()) { - // Do the this adjustment. - const llvm::Type *OrigTy = Callee->getType(); - Arg = DynamicTypeAdjust(Arg, Adjustment.ThisAdjustment); - - if (!Adjustment.ReturnAdjustment.isEmpty()) { - const CovariantThunkAdjustment &ReturnAdjustment = - CovariantThunkAdjustment(ThunkAdjustment(), - Adjustment.ReturnAdjustment); - - Callee = CGM.BuildCovariantThunk(GD, Extern, ReturnAdjustment); - - Callee = Builder.CreateBitCast(Callee, OrigTy); - ShouldAdjustReturnPointer = false; - } - } - - CallArgs.push_back(std::make_pair(RValue::get(Arg), ArgType)); - - for (FunctionDecl::param_const_iterator i = MD->param_begin(), - e = MD->param_end(); - i != e; ++i) { - ParmVarDecl *D = *i; - QualType ArgType = D->getType(); - - // llvm::Value *Arg = CGF.GetAddrOfLocalVar(Dst); - Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType.getNonReferenceType(), - SourceLocation()); - CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType)); - } - - RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs, - FPT->getCallConv(), - FPT->getNoReturnAttr()), - Callee, ReturnValueSlot(), CallArgs, MD); - if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) { - bool CanBeZero = !(ResultType->isReferenceType() - // FIXME: attr nonnull can't be zero either - /* || ResultType->hasAttr<NonNullAttr>() */ ); - // Do the return result adjustment. - if (CanBeZero) { - llvm::BasicBlock *NonZeroBlock = createBasicBlock(); - llvm::BasicBlock *ZeroBlock = createBasicBlock(); - llvm::BasicBlock *ContBlock = createBasicBlock(); - - const llvm::Type *Ty = RV.getScalarVal()->getType(); - llvm::Value *Zero = llvm::Constant::getNullValue(Ty); - Builder.CreateCondBr(Builder.CreateICmpNE(RV.getScalarVal(), Zero), - NonZeroBlock, ZeroBlock); - EmitBlock(NonZeroBlock); - llvm::Value *NZ = - DynamicTypeAdjust(RV.getScalarVal(), Adjustment.ReturnAdjustment); - EmitBranch(ContBlock); - EmitBlock(ZeroBlock); - llvm::Value *Z = RV.getScalarVal(); - EmitBlock(ContBlock); - llvm::PHINode *RVOrZero = Builder.CreatePHI(Ty); - RVOrZero->reserveOperandSpace(2); - RVOrZero->addIncoming(NZ, NonZeroBlock); - RVOrZero->addIncoming(Z, ZeroBlock); - RV = RValue::get(RVOrZero); - } else - RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), - Adjustment.ReturnAdjustment)); - } - - if (!ResultType->isVoidType()) - EmitReturnOfRValue(RV, ResultType); - - FinishFunction(); - return Fn; -} - -llvm::Constant * -CodeGenModule::GetAddrOfThunk(GlobalDecl GD, - const ThunkAdjustment &ThisAdjustment) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - // Compute mangled name - llvm::SmallString<256> OutName; - if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD)) - getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment, - OutName); - else - getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); - - // Get function for mangled name - const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); - return GetOrCreateLLVMFunction(OutName, Ty, GlobalDecl()); -} - -llvm::Constant * -CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD, - const CovariantThunkAdjustment &Adjustment) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - // Compute mangled name - llvm::SmallString<256> Name; - getMangleContext().mangleCovariantThunk(MD, Adjustment, Name); - - // Get function for mangled name - const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); - return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); -} - -void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) { - CGVtableInfo::AdjustmentVectorTy *AdjPtr = getVtableInfo().getAdjustments(GD); - if (!AdjPtr) - return; - CGVtableInfo::AdjustmentVectorTy &Adj = *AdjPtr; - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - for (unsigned i = 0; i < Adj.size(); i++) { - GlobalDecl OGD = Adj[i].first; - const CXXMethodDecl *OMD = cast<CXXMethodDecl>(OGD.getDecl()); - QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType(); - CanQualType oret = getContext().getCanonicalType(nc_oret); - QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType(); - CanQualType ret = getContext().getCanonicalType(nc_ret); - ThunkAdjustment ReturnAdjustment; - if (oret != ret) { - QualType qD = nc_ret->getPointeeType(); - QualType qB = nc_oret->getPointeeType(); - CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); - CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); - ReturnAdjustment = ComputeThunkAdjustment(D, B); - } - ThunkAdjustment ThisAdjustment = Adj[i].second; - bool Extern = !cast<CXXRecordDecl>(OMD->getDeclContext())->isInAnonymousNamespace(); - if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) { - CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment); - llvm::Constant *FnConst; - if (!ReturnAdjustment.isEmpty()) - FnConst = GetAddrOfCovariantThunk(GD, CoAdj); - else - FnConst = GetAddrOfThunk(GD, ThisAdjustment); - if (!isa<llvm::Function>(FnConst)) { - llvm::Constant *SubExpr = - cast<llvm::ConstantExpr>(FnConst)->getOperand(0); - llvm::Function *OldFn = cast<llvm::Function>(SubExpr); - llvm::Constant *NewFnConst; - if (!ReturnAdjustment.isEmpty()) - NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj); - else - NewFnConst = GetAddrOfThunk(GD, ThisAdjustment); - llvm::Function *NewFn = cast<llvm::Function>(NewFnConst); - NewFn->takeName(OldFn); - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(NewFn, OldFn->getType()); - OldFn->replaceAllUsesWith(NewPtrForOldDecl); - OldFn->eraseFromParent(); - FnConst = NewFn; - } - llvm::Function *Fn = cast<llvm::Function>(FnConst); - if (Fn->isDeclaration()) { - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::WeakAnyLinkage; - if (!Extern) - linktype = llvm::GlobalValue::InternalLinkage; - Fn->setLinkage(linktype); - if (!Features.Exceptions && !Features.ObjCNonFragileABI) - Fn->addFnAttr(llvm::Attribute::NoUnwind); - Fn->setAlignment(2); - CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj); - } - } - } -} - -llvm::Constant * -CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern, - const ThunkAdjustment &ThisAdjustment) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - llvm::SmallString<256> OutName; - if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(MD)) { - getMangleContext().mangleCXXDtorThunk(D, GD.getDtorType(), ThisAdjustment, - OutName); - } else - getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); - - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::WeakAnyLinkage; - if (!Extern) - linktype = llvm::GlobalValue::InternalLinkage; - llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::FunctionType *FTy = - getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - - llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(), - &getModule()); - CodeGenFunction(*this).GenerateThunk(Fn, GD, Extern, ThisAdjustment); - llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); - return m; -} - -llvm::Constant * -CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern, - const CovariantThunkAdjustment &Adjustment) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - llvm::SmallString<256> OutName; - getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::WeakAnyLinkage; - if (!Extern) - linktype = llvm::GlobalValue::InternalLinkage; - llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::FunctionType *FTy = - getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - - llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(), - &getModule()); - CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, Adjustment); - llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); - return m; -} - static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex, llvm::Value *This, const llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); @@ -618,17 +313,17 @@ llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty) { MD = MD->getCanonicalDecl(); - uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD); + uint64_t VTableIndex = CGM.getVTables().getMethodVtableIndex(MD); - return ::BuildVirtualCall(*this, VtableIndex, This, Ty); + return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *&This, const llvm::Type *Ty) { DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl()); - uint64_t VtableIndex = - CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type)); + uint64_t VTableIndex = + CGM.getVTables().getMethodVtableIndex(GlobalDecl(DD, Type)); - return ::BuildVirtualCall(*this, VtableIndex, This, Ty); + return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 072b1f6..cb1ecc1 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -67,8 +67,7 @@ const CGFunctionInfo & CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP) { return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(), llvm::SmallVector<CanQualType, 16>(), - FTNP->getCallConv(), - FTNP->getNoReturnAttr()); + FTNP->getExtInfo()); } /// \param Args - contains any initial parameters besides those @@ -81,8 +80,7 @@ static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT, ArgTys.push_back(FTP->getArgType(i)); CanQualType ResTy = FTP->getResultType().getUnqualifiedType(); return CGT.getFunctionInfo(ResTy, ArgTys, - FTP->getCallConv(), - FTP->getNoReturnAttr()); + FTP->getExtInfo()); } const CGFunctionInfo & @@ -175,8 +173,10 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { } return getFunctionInfo(GetReturnType(MD->getResultType()), ArgTys, - getCallingConventionForDecl(MD), - /*NoReturn*/ false); + FunctionType::ExtInfo( + /*NoReturn*/ false, + /*RegParm*/ 0, + getCallingConventionForDecl(MD))); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) { @@ -194,43 +194,40 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) { const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const CallArgList &Args, - CallingConv CC, - bool NoReturn) { + const FunctionType::ExtInfo &Info) { // FIXME: Kill copy. 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)); - return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn); + return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const FunctionArgList &Args, - CallingConv CC, - bool NoReturn) { + const FunctionType::ExtInfo &Info) { // FIXME: Kill copy. 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)); - return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn); + return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, const llvm::SmallVectorImpl<CanQualType> &ArgTys, - CallingConv CallConv, - bool NoReturn) { + const FunctionType::ExtInfo &Info) { #ifndef NDEBUG for (llvm::SmallVectorImpl<CanQualType>::const_iterator I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I) assert(I->isCanonicalAsParam()); #endif - unsigned CC = ClangCallConvToLLVMCallConv(CallConv); + unsigned CC = ClangCallConvToLLVMCallConv(Info.getCC()); // Lookup or create unique function info. llvm::FoldingSetNodeID ID; - CGFunctionInfo::Profile(ID, CC, NoReturn, ResTy, + CGFunctionInfo::Profile(ID, Info, ResTy, ArgTys.begin(), ArgTys.end()); void *InsertPos = 0; @@ -239,7 +236,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, return *FI; // Construct the function info. - FI = new CGFunctionInfo(CC, NoReturn, ResTy, ArgTys); + FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getRegParm(), ResTy, ArgTys); FunctionInfos.InsertNode(FI, InsertPos); // Compute ABI information. @@ -250,11 +247,12 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, bool _NoReturn, + unsigned _RegParm, CanQualType ResTy, const llvm::SmallVectorImpl<CanQualType> &ArgTys) : CallingConvention(_CallingConvention), EffectiveCallingConvention(_CallingConvention), - NoReturn(_NoReturn) + NoReturn(_NoReturn), RegParm(_RegParm) { NumArgs = ArgTys.size(); Args = new ArgInfo[1 + NumArgs]; @@ -610,11 +608,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, // FIXME: we need to honour command line settings also... // FIXME: RegParm should be reduced in case of nested functions and/or global // register variable. - signed RegParm = 0; - if (TargetDecl) - if (const RegparmAttr *RegParmAttr - = TargetDecl->getAttr<RegparmAttr>()) - RegParm = RegParmAttr->getNumParams(); + signed RegParm = FI.getRegParm(); unsigned PointerWidth = getContext().Target.getPointerWidth(0); for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), @@ -623,8 +617,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const ABIArgInfo &AI = it->info; unsigned Attributes = 0; - if (ParamType.isRestrictQualified()) - Attributes |= llvm::Attribute::NoAlias; + // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we + // have the corresponding parameter variable. It doesn't make + // sense to do it here because parameters are so fucked up. switch (AI.getKind()) { case ABIArgInfo::Coerce: @@ -749,6 +744,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, V = CreateMemTemp(Ty); Builder.CreateStore(AI, V); } else { + 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; {..." diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h index 3d81165..31c8aac 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -76,12 +76,16 @@ namespace CodeGen { unsigned NumArgs; ArgInfo *Args; + /// How many arguments to pass inreg. + unsigned RegParm; + public: typedef const ArgInfo *const_arg_iterator; typedef ArgInfo *arg_iterator; CGFunctionInfo(unsigned CallingConvention, bool NoReturn, + unsigned RegParm, CanQualType ResTy, const llvm::SmallVectorImpl<CanQualType> &ArgTys); ~CGFunctionInfo() { delete[] Args; } @@ -108,6 +112,8 @@ namespace CodeGen { EffectiveCallingConvention = Value; } + unsigned getRegParm() const { return RegParm; } + CanQualType getReturnType() const { return Args[0].type; } ABIArgInfo &getReturnInfo() { return Args[0].info; } @@ -116,19 +122,20 @@ namespace CodeGen { void Profile(llvm::FoldingSetNodeID &ID) { ID.AddInteger(getCallingConvention()); ID.AddBoolean(NoReturn); + ID.AddInteger(RegParm); getReturnType().Profile(ID); for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it) it->type.Profile(ID); } template<class Iterator> static void Profile(llvm::FoldingSetNodeID &ID, - unsigned CallingConvention, - bool NoReturn, + const FunctionType::ExtInfo &Info, CanQualType ResTy, Iterator begin, Iterator end) { - ID.AddInteger(CallingConvention); - ID.AddBoolean(NoReturn); + ID.AddInteger(Info.getCC()); + ID.AddBoolean(Info.getNoReturn()); + ID.AddInteger(Info.getRegParm()); ResTy.Profile(ID); for (; begin != end; ++begin) { CanQualType T = *begin; // force iterator to be over canonical types diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 525e858..177e862 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -69,42 +69,6 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class, return llvm::ConstantInt::get(PtrDiffTy, Offset); } -// FIXME: This probably belongs in CGVtable, but it relies on -// the static function ComputeNonVirtualBaseClassOffset, so we should make that -// a CodeGenModule member function as well. -ThunkAdjustment -CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl) { - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast<CXXRecordDecl *>(ClassDecl)-> - isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return ThunkAdjustment(); - } - - unsigned Start = 0; - uint64_t VirtualOffset = 0; - - const CXXBasePath &Path = Paths.front(); - const CXXRecordDecl *VBase = 0; - for (unsigned i = 0, e = Path.size(); i != e; ++i) { - const CXXBasePathElement& Element = Path[i]; - if (Element.Base->isVirtual()) { - Start = i+1; - QualType VBaseType = Element.Base->getType(); - VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl()); - } - } - if (VBase) - VirtualOffset = - getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); - - uint64_t Offset = - ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start); - return ThunkAdjustment(Offset, VirtualOffset); -} - /// Gets the address of a virtual base class within a complete object. /// This should only be used for (1) non-virtual bases or (2) virtual bases /// when the type is known to be complete (e.g. in complete destructors). @@ -139,7 +103,7 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo()); return V; -} +} llvm::Value * CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, @@ -308,6 +272,53 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, return Value; } +/// EmitCopyCtorCall - Emit a call to a copy constructor. +static void +EmitCopyCtorCall(CodeGenFunction &CGF, + const CXXConstructorDecl *CopyCtor, CXXCtorType CopyCtorType, + llvm::Value *ThisPtr, llvm::Value *VTT, llvm::Value *Src) { + llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, CopyCtorType); + + CallArgList CallArgs; + + // Push the this ptr. + CallArgs.push_back(std::make_pair(RValue::get(ThisPtr), + CopyCtor->getThisType(CGF.getContext()))); + + // Push the VTT parameter if necessary. + if (VTT) { + QualType T = CGF.getContext().getPointerType(CGF.getContext().VoidPtrTy); + CallArgs.push_back(std::make_pair(RValue::get(VTT), T)); + } + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + CopyCtor->getParamDecl(0)->getType())); + + + { + CodeGenFunction::CXXTemporariesCleanupScope Scope(CGF); + + // If the copy constructor has default arguments, emit them. + for (unsigned I = 1, E = CopyCtor->getNumParams(); I < E; ++I) { + const ParmVarDecl *Param = CopyCtor->getParamDecl(I); + const Expr *DefaultArgExpr = Param->getDefaultArg(); + + assert(DefaultArgExpr && "Ctor parameter must have default arg!"); + + QualType ArgType = Param->getType(); + CallArgs.push_back(std::make_pair(CGF.EmitCallArg(DefaultArgExpr, + ArgType), + ArgType)); + } + + const FunctionProtoType *FPT = + CopyCtor->getType()->getAs<FunctionProtoType>(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), + Callee, ReturnValueSlot(), CallArgs, CopyCtor); + } +} + /// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class /// array of objects from SrcValue to DestValue. Copying can be either a bitwise /// copy or via a copy constructor call. @@ -354,22 +365,9 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, if (BitwiseCopy) EmitAggregateCopy(Dest, Src, Ty); else if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0)) { - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, - Ctor_Complete); - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - BaseCopyCtor->getThisType(getContext()))); + BaseClassDecl->getCopyConstructor(getContext(), 0)) + EmitCopyCtorCall(*this, BaseCopyCtor, Ctor_Complete, Dest, 0, Src); - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - BaseCopyCtor->getParamDecl(0)->getType())); - const FunctionProtoType *FPT - = BaseCopyCtor->getType()->getAs<FunctionProtoType>(); - EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); - } EmitBlock(ContinueBlock); // Emit the increment of the loop counter. @@ -471,7 +469,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, /// GetVTTParameter - Return the VTT parameter that should be passed to a /// base constructor/destructor with virtual bases. static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { - if (!CGVtableInfo::needsVTTParameter(GD)) { + if (!CodeGenVTables::needsVTTParameter(GD)) { // This constructor/destructor does not need a VTT parameter. return 0; } @@ -486,21 +484,21 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { // If the record matches the base, this is the complete ctor/dtor // variant calling the base variant in a class with virtual bases. if (RD == Base) { - assert(!CGVtableInfo::needsVTTParameter(CGF.CurGD) && + assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) && "doing no-op VTT offset in base dtor/ctor?"); SubVTTIndex = 0; } else { - SubVTTIndex = CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base); + SubVTTIndex = CGF.CGM.getVTables().getSubVTTIndex(RD, Base); assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); } - if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) { + if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) { // A VTT parameter was passed to the constructor, use it. VTT = CGF.LoadCXXVTT(); VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex); } else { // We're the complete constructor, so get the VTT by name. - VTT = CGF.CGM.getVtableInfo().getVTT(RD); + VTT = CGF.CGM.getVTables().getVTT(RD); VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex); } @@ -531,29 +529,13 @@ void CodeGenFunction::EmitClassMemberwiseCopy( return; } - if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0)) { - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, CtorType); - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - BaseCopyCtor->getThisType(getContext()))); - - // Push the VTT parameter, if necessary. - if (llvm::Value *VTT = - GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType))) { - QualType T = getContext().getPointerType(getContext().VoidPtrTy); - CallArgs.push_back(std::make_pair(RValue::get(VTT), T)); - } + CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(getContext(), 0); + if (!BaseCopyCtor) + return; - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - BaseCopyCtor->getParamDecl(0)->getType())); - const FunctionProtoType *FPT = - BaseCopyCtor->getType()->getAs<FunctionProtoType>(); - EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); - } + llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType)); + EmitCopyCtorCall(*this, BaseCopyCtor, CtorType, Dest, VTT, Src); } /// EmitClassCopyAssignment - This routine generates code to copy assign a class @@ -690,7 +672,7 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { } } - InitializeVtablePtrs(ClassDecl); + InitializeVTablePointers(ClassDecl); } /// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator. @@ -1010,7 +992,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, MemberInitializers.push_back(Member); } - InitializeVtablePtrs(ClassDecl); + InitializeVTablePointers(ClassDecl); for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) { assert(LiveTemporaries.empty() && @@ -1060,7 +1042,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // Otherwise, we're in the base variant, so we need to ensure the // vtable ptrs are right before emitting the body. } else { - InitializeVtablePtrs(Dtor->getParent()); + InitializeVTablePointers(Dtor->getParent()); } // Emit the body of the statement. @@ -1286,14 +1268,12 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, // before the construction of the next array element, if any. // Keep track of the current number of live temporaries. - unsigned OldNumLiveTemporaries = LiveTemporaries.size(); + { + CXXTemporariesCleanupScope Scope(*this); - EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd); + EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd); + } - // Pop temporaries. - while (LiveTemporaries.size() > OldNumLiveTemporaries) - PopCXXTemporary(); - EmitBlock(ContinueBlock); // Emit the increment of the loop counter. @@ -1399,7 +1379,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount); QualType R = getContext().VoidTy; const CGFunctionInfo &FI - = CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); + = CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo()); const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, @@ -1474,7 +1454,7 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP)); - if (CGVtableInfo::needsVTTParameter(CurGD)) { + 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"); ++I; @@ -1541,7 +1521,7 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, VTablePtr = Builder.CreateLoad(VTablePtr, "vtable"); int64_t VBaseOffsetOffset = - CGM.getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); + CGM.getVTables().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); llvm::Value *VBaseOffsetPtr = Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset, "vbase.offset.ptr"); @@ -1556,69 +1536,126 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, return VBaseOffset; } -void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) { - if (!ClassDecl->isDynamicClass()) - return; +void +CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, + bool BaseIsMorallyVirtual, + llvm::Constant *VTable, + const CXXRecordDecl *VTableClass) { + const CXXRecordDecl *RD = Base.getBase(); + + // Compute the address point. + llvm::Value *VTableAddressPoint; + + // Check if we need to use a vtable from the VTT. + if (CodeGenVTables::needsVTTParameter(CurGD) && + (RD->getNumVBases() || BaseIsMorallyVirtual)) { + // Get the secondary vpointer index. + uint64_t VirtualPointerIndex = + CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base); + + /// Load the VTT. + llvm::Value *VTT = LoadCXXVTT(); + if (VirtualPointerIndex) + VTT = Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex); - llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl); - CGVtableInfo::AddrSubMap_t& AddressPoints = - *(*CGM.getVtableInfo().AddressPoints[ClassDecl])[ClassDecl]; - llvm::Value *ThisPtr = LoadCXXThis(); - const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl); + // And load the address point from the VTT. + VTableAddressPoint = Builder.CreateLoad(VTT); + } else { + uint64_t AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass); + VTableAddressPoint = + Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint); + } - // Store address points for virtual bases - for (CXXRecordDecl::base_class_const_iterator I = - ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) { - const CXXBaseSpecifier &Base = *I; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl); - InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints, - ThisPtr, Offset); + // Compute where to store the address point. + llvm::Value *VTableField; + + if (CodeGenVTables::needsVTTParameter(CurGD) && BaseIsMorallyVirtual) { + // We need to use the virtual base offset offset because the virtual base + // might have a different offset in the most derived class. + VTableField = GetAddressOfBaseClass(LoadCXXThis(), VTableClass, RD, + /*NullCheckValue=*/false); + } else { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + + VTableField = Builder.CreateBitCast(LoadCXXThis(), Int8PtrTy); + VTableField = + Builder.CreateConstInBoundsGEP1_64(VTableField, Base.getBaseOffset() / 8); } - // Store address points for non-virtual bases and current class - InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0); + // Finally, store the address point. + const llvm::Type *AddressPointPtrTy = + VTableAddressPoint->getType()->getPointerTo(); + VTableField = Builder.CreateBitCast(VTableField, AddressPointPtrTy); + Builder.CreateStore(VTableAddressPoint, VTableField); } -void CodeGenFunction::InitializeVtablePtrsRecursive( - const CXXRecordDecl *ClassDecl, - llvm::Constant *Vtable, - CGVtableInfo::AddrSubMap_t& AddressPoints, - llvm::Value *ThisPtr, - uint64_t Offset) { - if (!ClassDecl->isDynamicClass()) - return; +void +CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, + bool BaseIsMorallyVirtual, + bool BaseIsNonVirtualPrimaryBase, + llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + VisitedVirtualBasesSetTy& VBases) { + // If this base is a non-virtual primary base the address point has already + // been set. + if (!BaseIsNonVirtualPrimaryBase) { + // Initialize the vtable pointer for this base. + InitializeVTablePointer(Base, BaseIsMorallyVirtual, VTable, VTableClass); + } + + const CXXRecordDecl *RD = Base.getBase(); - // Store address points for non-virtual bases - const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl); - for (CXXRecordDecl::base_class_const_iterator I = - ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) { - const CXXBaseSpecifier &Base = *I; - if (Base.isVirtual()) + // Traverse bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + CXXRecordDecl *BaseDecl + = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Ignore classes without a vtable. + if (!BaseDecl->isDynamicClass()) continue; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl); - InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints, - ThisPtr, NewOffset); + + uint64_t BaseOffset; + bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; + bool BaseDeclIsNonVirtualPrimaryBase; + + if (I->isVirtual()) { + // Check if we've visited this virtual base before. + if (!VBases.insert(BaseDecl)) + continue; + + const ASTRecordLayout &Layout = + getContext().getASTRecordLayout(VTableClass); + + BaseOffset = Layout.getVBaseClassOffset(BaseDecl); + BaseDeclIsMorallyVirtual = true; + BaseDeclIsNonVirtualPrimaryBase = false; + } else { + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); + + BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); + BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl; + } + + InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset), + BaseDeclIsMorallyVirtual, + BaseDeclIsNonVirtualPrimaryBase, + VTable, VTableClass, VBases); } +} - // Compute the address point - assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) && - "Missing address point for class"); - uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)]; - llvm::Value *VtableAddressPoint = - Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint); - - // Compute the address to store the address point - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy); - VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8); - const llvm::Type *AddressPointPtrTy = - VtableAddressPoint->getType()->getPointerTo(); - VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy); +void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) { + // Ignore classes without a vtable. + if (!RD->isDynamicClass()) + return; + + // Get the VTable. + llvm::Constant *VTable = CGM.getVTables().GetAddrOfVTable(RD); - // Store address point - Builder.CreateStore(VtableAddressPoint, VtableField); + // Initialize the vtable pointers for this class and all of its bases. + VisitedVirtualBasesSetTy VBases; + InitializeVTablePointers(BaseSubobject(RD, 0), + /*BaseIsMorallyVirtual=*/false, + /*BaseIsNonVirtualPrimaryBase=*/false, + VTable, RD, VBases); } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index ad97d08..58acd3c 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -88,17 +88,35 @@ llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { /// getOrCreateFile - Get the file debug info descriptor for the input location. llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { - if (!Loc.isValid()) + if (!Loc.isValid()) // If Location is not valid then use main input file. return DebugFactory.CreateFile(TheCU.getFilename(), TheCU.getDirectory(), TheCU); SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + // Cache the results. + const char *fname = PLoc.getFilename(); + llvm::DenseMap<const char *, llvm::WeakVH>::iterator it = + DIFileCache.find(fname); + + if (it != DIFileCache.end()) { + // Verify that the information still exists. + if (&*it->second) + return llvm::DIFile(cast<llvm::MDNode>(it->second)); + } + + // FIXME: We shouldn't even need to call 'makeAbsolute()' in the cases + // where we can consult the FileEntry. llvm::sys::Path AbsFileName(PLoc.getFilename()); AbsFileName.makeAbsolute(); - return DebugFactory.CreateFile(AbsFileName.getLast(), - AbsFileName.getDirname(), TheCU); + llvm::DIFile F = DebugFactory.CreateFile(AbsFileName.getLast(), + AbsFileName.getDirname(), TheCU); + + DIFileCache[fname] = F.getNode(); + return F; + } /// CreateCompileUnit - Create new compile unit. void CGDebugInfo::CreateCompileUnit() { @@ -112,6 +130,10 @@ void CGDebugInfo::CreateCompileUnit() { llvm::sys::Path AbsFileName(MainFileName); AbsFileName.makeAbsolute(); + // The main file name provided via the "-main-file-name" option contains just + // the file name itself with no path information. This file name may have had + // a relative path, so we look into the actual file entry for the main + // file to determine the real absolute path for the file. std::string MainFileDir; if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) MainFileDir = MainFile->getDir()->getName(); @@ -604,7 +626,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, // It doesn't make sense to give a virtual destructor a vtable index, // since a single destructor has two entries in the vtable. if (!isa<CXXDestructorDecl>(Method)) - VIndex = CGM.getVtableInfo().getMethodVtableIndex(Method); + VIndex = CGM.getVTables().getMethodVtableIndex(Method); ContainingType = RecordTy; } @@ -662,7 +684,7 @@ 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.getVtableInfo().getVirtualBaseOffsetOffset(RD, Base); + BaseOffset = 0 - CGM.getVTables().getVirtualBaseOffsetOffset(RD, Base); BFlags = llvm::DIType::FlagVirtual; } else BaseOffset = RL.getBaseClassOffset(Base); @@ -692,10 +714,8 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) { ASTContext &Context = CGM.getContext(); /* Function type */ - llvm::SmallVector<llvm::DIDescriptor, 16> STys; - STys.push_back(getOrCreateType(Context.IntTy, Unit)); - llvm::DIArray SElements = - DebugFactory.GetOrCreateArray(STys.data(), STys.size()); + llvm::DIDescriptor STy = getOrCreateType(Context.IntTy, Unit); + llvm::DIArray SElements = DebugFactory.GetOrCreateArray(&STy, 1); llvm::DIType SubTy = DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type, Unit, "", Unit, @@ -1048,11 +1068,9 @@ llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, uint64_t NumElems = Ty->getNumElements(); if (NumElems > 0) --NumElems; - llvm::SmallVector<llvm::DIDescriptor, 8> Subscripts; - Subscripts.push_back(DebugFactory.GetOrCreateSubrange(0, NumElems)); - llvm::DIArray SubscriptArray = - DebugFactory.GetOrCreateArray(Subscripts.data(), Subscripts.size()); + llvm::DIDescriptor Subscript = DebugFactory.GetOrCreateSubrange(0, NumElems); + llvm::DIArray SubscriptArray = DebugFactory.GetOrCreateArray(&Subscript, 1); uint64_t Size = CGM.getContext().getTypeSize(Ty); uint64_t Align = CGM.getContext().getTypeAlign(Ty); @@ -1208,7 +1226,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, Ty = UnwrapTypeForDebugInfo(Ty); // Check for existing entry. - std::map<void *, llvm::WeakVH>::iterator it = + llvm::DenseMap<void *, llvm::WeakVH>::iterator it = TypeCache.find(Ty.getAsOpaquePtr()); if (it != TypeCache.end()) { // Verify that the debug info still exists. @@ -1371,13 +1389,10 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { llvm::DIFile Unit = getOrCreateFile(CurLoc); PresumedLoc PLoc = SM.getPresumedLoc(CurLoc); - llvm::DIDescriptor DR(RegionStack.back()); - llvm::DIScope DS = llvm::DIScope(DR.getNode()); - llvm::DILocation DO(NULL); - llvm::DILocation DL = - DebugFactory.CreateLocation(PLoc.getLine(), PLoc.getColumn(), - DS, DO); - Builder.SetCurrentDebugLocation(DL.getNode()); + llvm::MDNode *Scope = RegionStack.back(); + Builder.SetCurrentDebugLocation(llvm::NewDebugLoc::get(PLoc.getLine(), + PLoc.getColumn(), + Scope)); } /// EmitRegionStart- Constructs the debug code for entering a declarative @@ -1580,11 +1595,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, llvm::Instruction *Call = DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock()); - llvm::DIScope DS(RegionStack.back()); - llvm::DILocation DO(NULL); - llvm::DILocation DL = DebugFactory.CreateLocation(Line, Column, DS, DO); - - Call->setMetadata("dbg", DL.getNode()); + llvm::MDNode *Scope = RegionStack.back(); + Call->setDebugLoc(llvm::NewDebugLoc::get(Line, Column, Scope)); } /// EmitDeclare - Emit local variable declaration debug info. @@ -1646,13 +1658,9 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock()); - - llvm::DIScope DS(RegionStack.back()); - llvm::DILocation DO(NULL); - llvm::DILocation DL = - DebugFactory.CreateLocation(Line, PLoc.getColumn(), DS, DO); - Call->setMetadata("dbg", DL.getNode()); + llvm::MDNode *Scope = RegionStack.back(); + Call->setDebugLoc(llvm::NewDebugLoc::get(Line, PLoc.getColumn(), Scope)); } void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 47a4620..8397245 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -21,7 +21,6 @@ #include "llvm/Analysis/DebugInfo.h" #include "llvm/Support/ValueHandle.h" #include "llvm/Support/Allocator.h" -#include <map> #include "CGBuilder.h" @@ -52,8 +51,7 @@ class CGDebugInfo { unsigned FwdDeclCount; /// TypeCache - Cache of previously constructed Types. - // FIXME: Eliminate this map. Be careful of iterator invalidation. - std::map<void *, llvm::WeakVH> TypeCache; + llvm::DenseMap<void *, llvm::WeakVH> TypeCache; bool BlockLiteralGenericSet; llvm::DIType BlockLiteralGeneric; @@ -65,6 +63,7 @@ class CGDebugInfo { /// constructed on demand. For example, C++ destructors, C++ operators etc.. llvm::BumpPtrAllocator DebugInfoNames; + llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache; llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache; llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache; diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index dc9ecd6..87ec159 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -14,6 +14,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "CGCall.h" +#include "CGRecordLayout.h" #include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -1468,7 +1469,9 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, const FieldDecl* Field, unsigned CVRQualifiers) { - CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field); + const CGRecordLayout &RL = + CGM.getTypes().getCGRecordLayout(Field->getParent()); + const CGRecordLayout::BitFieldInfo &Info = RL.getBitFieldInfo(Field); // FIXME: CodeGenTypes should expose a method to get the appropriate type for // FieldTy (the appropriate type is ABI-dependent). @@ -1496,7 +1499,9 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, if (Field->isBitField()) return EmitLValueForBitfield(BaseValue, Field, CVRQualifiers); - unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); + const CGRecordLayout &RL = + CGM.getTypes().getCGRecordLayout(Field->getParent()); + unsigned idx = RL.getLLVMFieldNo(Field); llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp"); // Match union field type. @@ -1531,7 +1536,9 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value* BaseValue, if (!FieldType->isReferenceType()) return EmitLValueForField(BaseValue, Field, CVRQualifiers); - unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); + const CGRecordLayout &RL = + CGM.getTypes().getCGRecordLayout(Field->getParent()); + unsigned idx = RL.getLLVMFieldNo(Field); llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp"); assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); @@ -1637,6 +1644,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CastExpr::CK_AnyPointerToObjCPointerCast: return EmitLValue(E->getSubExpr()); + case CastExpr::CK_UncheckedDerivedToBase: case CastExpr::CK_DerivedToBase: { const RecordType *DerivedClassTy = E->getSubExpr()->getType()->getAs<RecordType>(); @@ -1872,7 +1880,6 @@ LValue CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) { LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { // Can only get l-value for message expression returning aggregate type RValue RV = EmitAnyExprToTemp(E); - // FIXME: can this be volatile? return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 4847ca3..e2e2cd0 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -333,8 +333,7 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { llvm::Value *FuncPtr; if (MD->isVirtual()) { - int64_t Index = - CGF.CGM.getVtableInfo().getMethodVtableIndex(MD); + int64_t Index = CGF.CGM.getVTables().getMethodVtableIndex(MD); // Itanium C++ ABI 2.3: // For a non-virtual function, this field is a simple function pointer. @@ -500,10 +499,6 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) { void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { llvm::Value *Val = DestPtr; - if (!Val) { - // Create a temporary variable. - Val = CGF.CreateMemTemp(E->getType(), "tmp"); - } CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer); } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 0328621..d9585c9 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -44,9 +44,8 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, QualType ResultType = FPT->getResultType(); return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args, - FPT->getCallConv(), - FPT->getNoReturnAttr()), Callee, - ReturnValue, Args, MD); + FPT->getExtInfo()), + Callee, ReturnValue, Args, MD); } /// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given @@ -411,7 +410,8 @@ static CharUnits CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { return CalculateCookiePadding(Ctx, E->getAllocatedType()); } -static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, +static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context, + CodeGenFunction &CGF, const CXXNewExpr *E, llvm::Value *& NumElements) { QualType Type = E->getAllocatedType(); @@ -432,6 +432,15 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, NumElements = llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue()); + while (const ArrayType *AType = Context.getAsArrayType(Type)) { + const llvm::ArrayType *llvmAType = + cast<llvm::ArrayType>(CGF.ConvertType(Type)); + NumElements = + CGF.Builder.CreateMul(NumElements, + llvm::ConstantInt::get( + SizeTy, llvmAType->getNumElements())); + Type = AType->getElementType(); + } return llvm::ConstantInt::get(SizeTy, AllocSize.getQuantity()); } @@ -444,6 +453,16 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, CGF.Builder.CreateMul(NumElements, llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity())); + + while (const ArrayType *AType = Context.getAsArrayType(Type)) { + const llvm::ArrayType *llvmAType = + cast<llvm::ArrayType>(CGF.ConvertType(Type)); + NumElements = + CGF.Builder.CreateMul(NumElements, + llvm::ConstantInt::get( + SizeTy, llvmAType->getNumElements())); + Type = AType->getElementType(); + } // And add the cookie padding if necessary. if (!CookiePadding.isZero()) @@ -504,7 +523,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { QualType SizeTy = getContext().getSizeType(); llvm::Value *NumElements = 0; - llvm::Value *AllocSize = EmitCXXNewAllocSize(*this, E, NumElements); + llvm::Value *AllocSize = EmitCXXNewAllocSize(getContext(), + *this, E, NumElements); NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy)); @@ -590,10 +610,20 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { CookiePadding.getQuantity()); } - NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); - - EmitNewInitializer(*this, E, NewPtr, NumElements); - + if (AllocType->isArrayType()) { + while (const ArrayType *AType = getContext().getAsArrayType(AllocType)) + AllocType = AType->getElementType(); + NewPtr = + Builder.CreateBitCast(NewPtr, + ConvertType(getContext().getPointerType(AllocType))); + EmitNewInitializer(*this, E, NewPtr, NumElements); + NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); + } + else { + NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); + EmitNewInitializer(*this, E, NewPtr, NumElements); + } + if (NullCheckResult) { Builder.CreateBr(NewEnd); NewNotNull = Builder.GetInsertBlock(); diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 5915340..0a0c914 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -522,13 +522,21 @@ EmitCompoundAssign(const CompoundAssignOperator *E, // scalar. OpInfo.Ty = E->getComputationResultType(); OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty); - + LValue LHSLV = CGF.EmitLValue(E->getLHS()); - - // We know the LHS is a complex lvalue. - OpInfo.LHS=EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified()); - OpInfo.LHS=EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty); + ComplexPairTy LHSComplexPair; + if (LHSLV.isPropertyRef()) + LHSComplexPair = + CGF.EmitObjCPropertyGet(LHSLV.getPropertyRefExpr()).getComplexVal(); + else if (LHSLV.isKVCRef()) + LHSComplexPair = + CGF.EmitObjCPropertyGet(LHSLV.getKVCRefExpr()).getComplexVal(); + else + LHSComplexPair = EmitLoadOfComplex(LHSLV.getAddress(), + LHSLV.isVolatileQualified()); + + OpInfo.LHS=EmitComplexToComplexCast(LHSComplexPair, LHSTy, OpInfo.Ty); // Expand the binary operator. ComplexPairTy Result = (this->*Func)(OpInfo); @@ -537,12 +545,22 @@ EmitCompoundAssign(const CompoundAssignOperator *E, Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy); // Store the result value into the LHS lvalue. - EmitStoreOfComplex(Result, LHSLV.getAddress(), LHSLV.isVolatileQualified()); + if (LHSLV.isPropertyRef()) + CGF.EmitObjCPropertySet(LHSLV.getPropertyRefExpr(), + RValue::getComplex(Result)); + else if (LHSLV.isKVCRef()) + CGF.EmitObjCPropertySet(LHSLV.getKVCRefExpr(), RValue::getComplex(Result)); + else + EmitStoreOfComplex(Result, LHSLV.getAddress(), LHSLV.isVolatileQualified()); // And now return the LHS IgnoreReal = ignreal; IgnoreImag = ignimag; IgnoreRealAssign = ignreal; IgnoreImagAssign = ignimag; + if (LHSLV.isPropertyRef()) + return CGF.EmitObjCPropertyGet(LHSLV.getPropertyRefExpr()).getComplexVal(); + else if (LHSLV.isKVCRef()) + return CGF.EmitObjCPropertyGet(LHSLV.getKVCRefExpr()).getComplexVal(); return EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified()); } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index f0d82a8..172a77d 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -14,6 +14,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "CGObjCRuntime.h" +#include "CGRecordLayout.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" @@ -417,7 +418,7 @@ public: // Get the function pointer (or index if this is a virtual function). if (MD->isVirtual()) { - uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); + uint64_t Index = CGM.getVTables().getMethodVtableIndex(MD); // Itanium C++ ABI 2.3: // For a non-virtual function, this field is a simple function pointer. @@ -1011,7 +1012,9 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { E = RD->field_end(); I != E; ++I) { const FieldDecl *FD = *I; - unsigned FieldNo = getTypes().getLLVMFieldNo(FD); + const CGRecordLayout &RL = + getTypes().getCGRecordLayout(FD->getParent()); + unsigned FieldNo = RL.getLLVMFieldNo(FD); Elements[FieldNo] = EmitNullConstant(FD->getType()); } @@ -1047,7 +1050,9 @@ CodeGenModule::EmitPointerToDataMember(const FieldDecl *FD) { const llvm::StructType *ClassLTy = cast<llvm::StructType>(getTypes().ConvertType(ClassType)); - unsigned FieldNo = getTypes().getLLVMFieldNo(FD); + const CGRecordLayout &RL = + getTypes().getCGRecordLayout(FD->getParent()); + unsigned FieldNo = RL.getLLVMFieldNo(FD); uint64_t Offset = getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 7e26971..42bf68e 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -769,6 +769,9 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { static bool ShouldNullCheckClassCastValue(const CastExpr *CE) { const Expr *E = CE->getSubExpr(); + + if (CE->getCastKind() == CastExpr::CK_UncheckedDerivedToBase) + return false; if (isa<CXXThisExpr>(E)) { // We always assume that 'this' is never null. @@ -826,6 +829,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl, NullCheckValue); } + case CastExpr::CK_UncheckedDerivedToBase: case CastExpr::CK_DerivedToBase: { const RecordType *DerivedClassTy = E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>(); @@ -1337,6 +1341,11 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFSub(Ops.LHS, Ops.RHS, "sub"); + + // Signed integer overflow is undefined behavior. + if (Ops.Ty->isSignedIntegerType()) + return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub"); + return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub"); } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 3ff77f0..9eaf57c 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -191,7 +191,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, // 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, - CC_Default, false), + FunctionType::ExtInfo()), GetPropertyFn, ReturnValueSlot(), Args); // We need to fix the type here. Ivars with copy & retain are // always objects so we don't need to worry about complex or @@ -201,7 +201,12 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, EmitReturnOfRValue(RV, PD->getType()); } else { LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); - if (hasAggregateLLVMType(Ivar->getType())) { + if (Ivar->getType()->isAnyComplexType()) { + ComplexPairTy Pair = LoadComplexFromAddr(LV.getAddress(), + LV.isVolatileQualified()); + StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified()); + } + else if (hasAggregateLLVMType(Ivar->getType())) { EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); } else { CodeGenTypes &Types = CGM.getTypes(); @@ -280,7 +285,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, // 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, - CC_Default, false), SetPropertyFn, + FunctionType::ExtInfo()), + SetPropertyFn, ReturnValueSlot(), Args); } else { // FIXME: Find a clean way to avoid AST node creation. @@ -459,12 +465,13 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ static const unsigned NumItems = 16; // Get selector - llvm::SmallVector<IdentifierInfo*, 3> II; - II.push_back(&CGM.getContext().Idents.get("countByEnumeratingWithState")); - II.push_back(&CGM.getContext().Idents.get("objects")); - II.push_back(&CGM.getContext().Idents.get("count")); - Selector FastEnumSel = CGM.getContext().Selectors.getSelector(II.size(), - &II[0]); + IdentifierInfo *II[] = { + &CGM.getContext().Idents.get("countByEnumeratingWithState"), + &CGM.getContext().Idents.get("objects"), + &CGM.getContext().Idents.get("count") + }; + Selector FastEnumSel = + CGM.getContext().Selectors.getSelector(llvm::array_lengthof(II), &II[0]); QualType ItemsTy = getContext().getConstantArrayType(getContext().getObjCIdType(), @@ -555,7 +562,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ // 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, - CC_Default, false), + FunctionType::ExtInfo()), EnumerationMutationFn, ReturnValueSlot(), Args2); EmitBlock(WasNotMutated); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 119819b..d445200 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -465,7 +465,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, - CC_Default, false); + FunctionType::ExtInfo()); const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); @@ -573,7 +573,7 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, - CC_Default, false); + FunctionType::ExtInfo()); const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); @@ -1694,7 +1694,7 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { Params.push_back(ASTIdTy); const llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, - CC_Default, false), false); + FunctionType::ExtInfo()), false); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 475280b..883ed98 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -13,6 +13,7 @@ #include "CGObjCRuntime.h" +#include "CGRecordLayout.h" #include "CodeGenModule.h" #include "CodeGenFunction.h" #include "clang/AST/ASTContext.h" @@ -306,7 +307,8 @@ public: Params.push_back(Ctx.BoolTy); const llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(IdType, Params, - CC_Default, false), false); + FunctionType::ExtInfo()), + false); return CGM.CreateRuntimeFunction(FTy, "objc_getProperty"); } @@ -325,7 +327,8 @@ public: Params.push_back(Ctx.BoolTy); const llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, - CC_Default, false), false); + FunctionType::ExtInfo()), + false); return CGM.CreateRuntimeFunction(FTy, "objc_setProperty"); } @@ -337,7 +340,8 @@ public: Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType())); const llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, - CC_Default, false), false); + FunctionType::ExtInfo()), + false); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } @@ -1559,7 +1563,7 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, - CC_Default, false); + FunctionType::ExtInfo()); const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); @@ -3131,8 +3135,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, FieldDecl *Field = RecFields[i]; uint64_t FieldOffset; if (RD) { + const CGRecordLayout &RL = + CGM.getTypes().getCGRecordLayout(Field->getParent()); if (Field->isBitField()) { - CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field); + const CGRecordLayout::BitFieldInfo &Info = RL.getBitFieldInfo(Field); const llvm::Type *Ty = CGM.getTypes().ConvertTypeForMemRecursive(Field->getType()); @@ -3141,7 +3147,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, FieldOffset = Info.FieldNo * TypeSize; } else FieldOffset = - Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field)); + Layout->getElementOffset(RL.getLLVMFieldNo(Field)); } else FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field)); @@ -5094,7 +5100,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( // FIXME. This is too much work to get the ABI-specific result type needed to // find the message name. const CGFunctionInfo &FnInfo - = Types.getFunctionInfo(ResultType, CallArgList(), CC_Default, false); + = Types.getFunctionInfo(ResultType, CallArgList(), + FunctionType::ExtInfo()); llvm::Constant *Fn = 0; std::string Name("\01l_"); if (CGM.ReturnTypeUsesSret(FnInfo)) { @@ -5169,7 +5176,7 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( ObjCTypes.MessageRefCPtrTy)); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs, - CC_Default, false); + FunctionType::ExtInfo()); llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0); Callee = CGF.Builder.CreateLoad(Callee); const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true); diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index ff5d40b..b781940 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -16,7 +16,6 @@ #ifndef CLANG_CODEGEN_OBCJRUNTIME_H #define CLANG_CODEGEN_OBCJRUNTIME_H #include "clang/Basic/IdentifierTable.h" // Selector -#include "llvm/ADT/SmallVector.h" #include "clang/AST/DeclObjC.h" #include <string> diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 4907223..1caec97 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -148,7 +148,7 @@ public: }; /// BuildTypeInfo - Build the RTTI type info struct for the given type. - llvm::Constant *BuildTypeInfo(QualType Ty); + llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false); }; } @@ -327,83 +327,20 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) { if (ContainsIncompleteClassType(Ty)) return llvm::GlobalValue::InternalLinkage; - switch (Ty->getTypeClass()) { - default: - // FIXME: We need to add code to handle all types. - assert(false && "Unhandled type!"); - break; - - case Type::Pointer: { - const PointerType *PointerTy = cast<PointerType>(Ty); - - // If the pointee type has internal linkage, then the pointer type needs to - // have it as well. - if (getTypeInfoLinkage(PointerTy->getPointeeType()) == - llvm::GlobalVariable::InternalLinkage) - return llvm::GlobalVariable::InternalLinkage; - - return llvm::GlobalVariable::WeakODRLinkage; - } - - case Type::Enum: { - const EnumType *EnumTy = cast<EnumType>(Ty); - const EnumDecl *ED = EnumTy->getDecl(); - - // If we're in an anonymous namespace, then we always want internal linkage. - if (ED->isInAnonymousNamespace() || !ED->hasLinkage()) - return llvm::GlobalVariable::InternalLinkage; - - return llvm::GlobalValue::WeakODRLinkage; - } - - case Type::Record: { - const RecordType *RecordTy = cast<RecordType>(Ty); - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); - - // If we're in an anonymous namespace, then we always want internal linkage. - if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) - return llvm::GlobalVariable::InternalLinkage; - - // If this class does not have a vtable, we want weak linkage. - if (!RD->isDynamicClass()) - return llvm::GlobalValue::WeakODRLinkage; - - return CodeGenModule::getVtableLinkage(RD); - } - - case Type::Vector: - case Type::ExtVector: - case Type::Builtin: - return llvm::GlobalValue::WeakODRLinkage; - - case Type::FunctionProto: { - const FunctionProtoType *FPT = cast<FunctionProtoType>(Ty); + switch (Ty->getLinkage()) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: + return llvm::GlobalValue::InternalLinkage; - // Check the return type. - if (getTypeInfoLinkage(FPT->getResultType()) == - llvm::GlobalValue::InternalLinkage) - return llvm::GlobalValue::InternalLinkage; - - // Check the parameter types. - for (unsigned i = 0; i != FPT->getNumArgs(); ++i) { - if (getTypeInfoLinkage(FPT->getArgType(i)) == - llvm::GlobalValue::InternalLinkage) - return llvm::GlobalValue::InternalLinkage; + case ExternalLinkage: + if (const RecordType *Record = dyn_cast<RecordType>(Ty)) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); + if (RD->isDynamicClass()) + return CodeGenModule::getVtableLinkage(RD); } - - return llvm::GlobalValue::WeakODRLinkage; - } - - case Type::ConstantArray: - case Type::IncompleteArray: { - const ArrayType *AT = cast<ArrayType>(Ty); - - // Check the element type. - if (getTypeInfoLinkage(AT->getElementType()) == - llvm::GlobalValue::InternalLinkage) - return llvm::GlobalValue::InternalLinkage; - } + return llvm::GlobalValue::WeakODRLinkage; } return llvm::GlobalValue::WeakODRLinkage; @@ -444,6 +381,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { switch (Ty->getTypeClass()) { default: assert(0 && "Unhandled type!"); + case Type::Builtin: // GCC treats vector types as fundamental types. case Type::Vector: case Type::ExtVector: @@ -511,7 +449,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { Fields.push_back(Vtable); } -llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) { +llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { // We want to operate on the canonical type. Ty = CGM.getContext().getCanonicalType(Ty); @@ -525,7 +463,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) { return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy); // Check if there is already an external RTTI descriptor for this type. - if (ShouldUseExternalRTTIDescriptor(Ty)) + if (!Force && ShouldUseExternalRTTIDescriptor(Ty)) return GetAddrOfExternalRTTIDescriptor(Ty); llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty); @@ -538,11 +476,9 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) { switch (Ty->getTypeClass()) { default: assert(false && "Unhandled type class!"); - case Type::Builtin: - assert(false && "Builtin type info must be in the standard library!"); - break; // GCC treats vector types as fundamental types. + case Type::Builtin: case Type::Vector: case Type::ExtVector: // Itanium C++ ABI 2.9.5p4: @@ -760,7 +696,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { // subobject. For a virtual base, this is the offset in the virtual table of // the virtual base offset for the virtual base referenced (negative). if (Base->isVirtual()) - OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetOffset(RD, BaseDecl); + OffsetFlags = CGM.getVTables().getVirtualBaseOffsetOffset(RD, BaseDecl); else { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); OffsetFlags = Layout.getBaseClassOffset(BaseDecl) / 8; @@ -854,3 +790,61 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) { return RTTIBuilder(*this).BuildTypeInfo(Ty); } + +// Try to find the magic class __cxxabiv1::__fundamental_type_info. If +// exists and has a destructor, we will emit the typeinfo for the fundamental +// types. This is the same behaviour as GCC. +static CXXRecordDecl *FindMagicClass(ASTContext &AC) { + const IdentifierInfo &NamespaceII = AC.Idents.get("__cxxabiv1"); + DeclarationName NamespaceDN = AC.DeclarationNames.getIdentifier(&NamespaceII); + TranslationUnitDecl *TUD = AC.getTranslationUnitDecl(); + DeclContext::lookup_result NamespaceLookup = TUD->lookup(NamespaceDN); + if (NamespaceLookup.first == NamespaceLookup.second) + return NULL; + const NamespaceDecl *Namespace = + dyn_cast<NamespaceDecl>(*NamespaceLookup.first); + if (!Namespace) + return NULL; + + const IdentifierInfo &ClassII = AC.Idents.get("__fundamental_type_info"); + DeclarationName ClassDN = AC.DeclarationNames.getIdentifier(&ClassII); + DeclContext::lookup_const_result ClassLookup = Namespace->lookup(ClassDN); + if (ClassLookup.first == ClassLookup.second) + return NULL; + CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(*ClassLookup.first); + + if (Class->hasDefinition() && Class->isDynamicClass() && + Class->getDestructor(AC)) + return Class; + + return NULL; +} + +void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) { + QualType PointerType = Context.getPointerType(Type); + QualType PointerTypeConst = Context.getPointerType(Type.withConst()); + RTTIBuilder(*this).BuildTypeInfo(Type, true); + RTTIBuilder(*this).BuildTypeInfo(PointerType, true); + RTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true); +} + +void CodeGenModule::EmitFundamentalRTTIDescriptors() { + CXXRecordDecl *RD = FindMagicClass(getContext()); + if (!RD) + return; + + getVTables().GenerateClassData(getVtableLinkage(RD), RD); + + QualType FundamentalTypes[] = { Context.VoidTy, Context.Char32Ty, + Context.Char16Ty, Context.UnsignedLongLongTy, + Context.LongLongTy, Context.WCharTy, + Context.UnsignedShortTy, Context.ShortTy, + Context.UnsignedLongTy, Context.LongTy, + Context.UnsignedIntTy, Context.IntTy, + Context.UnsignedCharTy, Context.FloatTy, + Context.LongDoubleTy, Context.DoubleTy, + Context.CharTy, Context.BoolTy, + Context.SignedCharTy }; + for (unsigned i = 0; i < sizeof(FundamentalTypes)/sizeof(QualType); ++i) + EmitFundamentalRTTIDescriptor(FundamentalTypes[i]); +} diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h new file mode 100644 index 0000000..d0d8f98 --- /dev/null +++ b/lib/CodeGen/CGRecordLayout.h @@ -0,0 +1,95 @@ +//===--- CGRecordLayout.h - LLVM Record Layout Information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGRECORDLAYOUT_H +#define CLANG_CODEGEN_CGRECORDLAYOUT_H + +#include "llvm/ADT/DenseMap.h" +#include "clang/AST/Decl.h" +namespace llvm { + class Type; +} + +namespace clang { +namespace CodeGen { + +/// CGRecordLayout - This class handles struct and union layout info while +/// lowering AST types to LLVM types. +/// +/// These layout objects are only created on demand as IR generation requires. +class CGRecordLayout { + friend class CodeGenTypes; + + CGRecordLayout(const CGRecordLayout&); // DO NOT IMPLEMENT + void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT + +public: + struct BitFieldInfo { + BitFieldInfo(unsigned FieldNo, + unsigned Start, + unsigned Size) + : FieldNo(FieldNo), Start(Start), Size(Size) {} + + unsigned FieldNo; + unsigned Start; + unsigned Size; + }; + +private: + /// The LLVMType corresponding to this record layout. + const llvm::Type *LLVMType; + + /// Map from (non-bit-field) struct field to the corresponding llvm struct + /// type field no. This info is populated by record builder. + llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo; + + /// Map from (bit-field) struct field to the corresponding llvm struct type + /// field no. This info is populated by record builder. + llvm::DenseMap<const FieldDecl *, BitFieldInfo> BitFields; + + /// Whether one of the fields in this record layout is a pointer to data + /// member, or a struct that contains pointer to data member. + bool ContainsPointerToDataMember : 1; + +public: + CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember) + : LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) {} + + /// \brief Return the LLVM type associated with this record. + const llvm::Type *getLLVMType() const { + return LLVMType; + } + + /// \brief Check whether this struct contains pointers to data members. + bool containsPointerToDataMember() const { + return ContainsPointerToDataMember; + } + + /// \brief Return the BitFieldInfo that corresponds to the field FD. + unsigned getLLVMFieldNo(const FieldDecl *FD) const { + assert(!FD->isBitField() && "Invalid call for bit-field decl!"); + assert(FieldInfo.count(FD) && "Invalid field for record!"); + return FieldInfo.lookup(FD); + } + + /// \brief Return llvm::StructType element number that corresponds to the + /// field FD. + const BitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const { + assert(FD->isBitField() && "Invalid call for non bit-field decl!"); + llvm::DenseMap<const FieldDecl *, BitFieldInfo>::const_iterator + it = BitFields.find(FD); + assert(it != BitFields.end() && "Unable to find bitfield info"); + return it->second; + } +}; + +} // end namespace CodeGen +} // end namespace clang + +#endif diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index baafd68..daebabd 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -1,4 +1,4 @@ -//===--- CGRecordLayoutBuilder.cpp - Record builder helper ------*- C++ -*-===// +//===--- CGRecordLayoutBuilder.cpp - CGRecordLayout builder ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,25 +7,131 @@ // //===----------------------------------------------------------------------===// // -// This is a helper class used to build CGRecordLayout objects and LLVM types. +// Builder implementation for CGRecordLayout objects. // //===----------------------------------------------------------------------===// -#include "CGRecordLayoutBuilder.h" - +#include "CGRecordLayout.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "CodeGenTypes.h" +#include "llvm/Type.h" #include "llvm/DerivedTypes.h" #include "llvm/Target/TargetData.h" - - using namespace clang; using namespace CodeGen; +namespace clang { +namespace CodeGen { + +class CGRecordLayoutBuilder { +public: + /// FieldTypes - Holds the LLVM types that the struct is created from. + std::vector<const llvm::Type *> FieldTypes; + + /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number. + typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo; + llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields; + + /// LLVMBitFieldInfo - Holds location and size information about a bit field. + struct LLVMBitFieldInfo { + LLVMBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, unsigned Start, + unsigned Size) + : FD(FD), FieldNo(FieldNo), Start(Start), Size(Size) { } + + const FieldDecl *FD; + + unsigned FieldNo; + unsigned Start; + unsigned Size; + }; + llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields; + + /// ContainsPointerToDataMember - Whether one of the fields in this record + /// layout is a pointer to data member, or a struct that contains pointer to + /// data member. + bool ContainsPointerToDataMember; + + /// Packed - Whether the resulting LLVM struct will be packed or not. + bool Packed; + +private: + CodeGenTypes &Types; + + /// Alignment - Contains the alignment of the RecordDecl. + // + // FIXME: This is not needed and should be removed. + unsigned Alignment; + + /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the + /// LLVM types. + unsigned AlignmentAsLLVMStruct; + + /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field, + /// this will have the number of bits still available in the field. + char BitsAvailableInLastField; + + /// NextFieldOffsetInBytes - Holds the next field offset in bytes. + uint64_t NextFieldOffsetInBytes; + + /// LayoutUnion - Will layout a union RecordDecl. + void LayoutUnion(const RecordDecl *D); + + /// LayoutField - try to layout all fields in the record decl. + /// Returns false if the operation failed because the struct is not packed. + bool LayoutFields(const RecordDecl *D); + + /// LayoutBases - layout the bases and vtable pointer of a record decl. + void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout); + + /// LayoutField - layout a single field. Returns false if the operation failed + /// because the current struct is not packed. + bool LayoutField(const FieldDecl *D, uint64_t FieldOffset); + + /// LayoutBitField - layout a single bit field. + void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset); + + /// AppendField - Appends a field with the given offset and type. + void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); + + /// AppendPadding - Appends enough padding bytes so that the total struct + /// size matches the alignment of the passed in type. + void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); + + /// AppendPadding - Appends enough padding bytes so that the total + /// struct size is a multiple of the field alignment. + void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment); + + /// AppendBytes - Append a given number of bytes to the record. + void AppendBytes(uint64_t NumBytes); + + /// AppendTailPadding - Append enough tail padding so that the type will have + /// the passed size. + void AppendTailPadding(uint64_t RecordSize); + + unsigned getTypeAlignment(const llvm::Type *Ty) const; + uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const; + + /// CheckForPointerToDataMember - Check if the given type contains a pointer + /// to data member. + void CheckForPointerToDataMember(QualType T); + +public: + CGRecordLayoutBuilder(CodeGenTypes &Types) + : ContainsPointerToDataMember(false), Packed(false), Types(Types), + Alignment(0), AlignmentAsLLVMStruct(1), + BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { } + + /// Layout - Will layout a RecordDecl. + void Layout(const RecordDecl *D); +}; + +} +} + void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8; Packed = D->hasAttr<PackedAttr>(); @@ -110,7 +216,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, // Check if we have a pointer to data member in this field. CheckForPointerToDataMember(D->getType()); - + assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!"); uint64_t FieldOffsetInBytes = FieldOffset / 8; @@ -166,7 +272,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { unsigned Align = 0; bool HasOnlyZeroSizedBitFields = true; - + unsigned FieldNo = 0; for (RecordDecl::field_iterator Field = D->field_begin(), FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { @@ -182,12 +288,13 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { continue; // Add the bit field info. - Types.addBitFieldInfo(*Field, 0, 0, FieldSize); - } else - Types.addFieldInfo(*Field, 0); + LLVMBitFields.push_back(LLVMBitFieldInfo(*Field, 0, 0, FieldSize)); + } else { + LLVMFields.push_back(LLVMFieldInfo(*Field, 0)); + } HasOnlyZeroSizedBitFields = false; - + const llvm::Type *FieldTy = Types.ConvertTypeForMemRecursive(Field->getType()); unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy); @@ -218,7 +325,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { "0-align record did not have all zero-sized bit-fields!"); Align = 1; } - + // Append tail padding. if (Layout.getSize() / 8 > Size) AppendPadding(Layout.getSize() / 8, Align); @@ -228,9 +335,9 @@ void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout) { // Check if we need to add a vtable pointer. if (RD->isDynamicClass() && !Layout.getPrimaryBase()) { - const llvm::Type *Int8PtrTy = + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(Types.getLLVMContext()); - + assert(NextFieldOffsetInBytes == 0 && "Vtable pointer must come first!"); AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo()); @@ -245,7 +352,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) LayoutBases(RD, Layout); - + unsigned FieldNo = 0; for (RecordDecl::field_iterator Field = D->field_begin(), @@ -269,14 +376,14 @@ void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) { uint64_t RecordSizeInBytes = RecordSize / 8; assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); - uint64_t AlignedNextFieldOffset = + uint64_t AlignedNextFieldOffset = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct); if (AlignedNextFieldOffset == RecordSizeInBytes) { // We don't need any padding. return; } - + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; AppendBytes(NumPadBytes); } @@ -359,46 +466,49 @@ void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) { } } else if (const RecordType *RT = T->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - + // FIXME: It would be better if there was a way to explicitly compute the // record layout instead of converting to a type. Types.ConvertTagDeclType(RD); - + const CGRecordLayout &Layout = Types.getCGRecordLayout(RD); - + if (Layout.containsPointerToDataMember()) ContainsPointerToDataMember = true; - } + } } -CGRecordLayout * -CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types, - const RecordDecl *D) { - CGRecordLayoutBuilder Builder(Types); +CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { + CGRecordLayoutBuilder Builder(*this); Builder.Layout(D); - const llvm::Type *Ty = llvm::StructType::get(Types.getLLVMContext(), + const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(), Builder.FieldTypes, Builder.Packed); - assert(Types.getContext().getASTRecordLayout(D).getSize() / 8 == - Types.getTargetData().getTypeAllocSize(Ty) && + assert(getContext().getASTRecordLayout(D).getSize() / 8 == + getTargetData().getTypeAllocSize(Ty) && "Type size mismatch!"); + CGRecordLayout *RL = + new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); + // Add all the field numbers. for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i) { const FieldDecl *FD = Builder.LLVMFields[i].first; unsigned FieldNo = Builder.LLVMFields[i].second; - Types.addFieldInfo(FD, FieldNo); + RL->FieldInfo.insert(std::make_pair(FD, FieldNo)); } // Add bitfield info. for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) { - const LLVMBitFieldInfo &Info = Builder.LLVMBitFields[i]; + const CGRecordLayoutBuilder::LLVMBitFieldInfo &Info = + Builder.LLVMBitFields[i]; - Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size); + CGRecordLayout::BitFieldInfo BFI(Info.FieldNo, Info.Start, Info.Size); + RL->BitFields.insert(std::make_pair(Info.FD, BFI)); } - return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); + return RL; } diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h deleted file mode 100644 index eb60ed7..0000000 --- a/lib/CodeGen/CGRecordLayoutBuilder.h +++ /dev/null @@ -1,142 +0,0 @@ -//===--- CGRecordLayoutBuilder.h - Record builder helper --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a helper class used to build CGRecordLayout objects and LLVM types. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H -#define CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/System/DataTypes.h" -#include <vector> - -namespace llvm { - class Type; -} - -namespace clang { - class ASTRecordLayout; - class CXXRecordDecl; - class FieldDecl; - class RecordDecl; - class QualType; - -namespace CodeGen { - class CGRecordLayout; - class CodeGenTypes; - -class CGRecordLayoutBuilder { - CodeGenTypes &Types; - - /// Packed - Whether the resulting LLVM struct will be packed or not. - bool Packed; - - /// ContainsPointerToDataMember - Whether one of the fields in this record - /// layout is a pointer to data member, or a struct that contains pointer to - /// data member. - bool ContainsPointerToDataMember; - - /// Alignment - Contains the alignment of the RecordDecl. - unsigned Alignment; - - /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the - /// LLVM types. - unsigned AlignmentAsLLVMStruct; - - /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field, - /// this will have the number of bits still available in the field. - char BitsAvailableInLastField; - - /// NextFieldOffsetInBytes - Holds the next field offset in bytes. - uint64_t NextFieldOffsetInBytes; - - /// FieldTypes - Holds the LLVM types that the struct is created from. - std::vector<const llvm::Type *> FieldTypes; - - /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number. - typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo; - llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields; - - /// LLVMBitFieldInfo - Holds location and size information about a bit field. - struct LLVMBitFieldInfo { - LLVMBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, unsigned Start, - unsigned Size) - : FD(FD), FieldNo(FieldNo), Start(Start), Size(Size) { } - - const FieldDecl *FD; - - unsigned FieldNo; - unsigned Start; - unsigned Size; - }; - llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields; - - CGRecordLayoutBuilder(CodeGenTypes &Types) - : Types(Types), Packed(false), ContainsPointerToDataMember(false) - , Alignment(0), AlignmentAsLLVMStruct(1) - , BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { } - - /// Layout - Will layout a RecordDecl. - void Layout(const RecordDecl *D); - - /// LayoutUnion - Will layout a union RecordDecl. - void LayoutUnion(const RecordDecl *D); - - /// LayoutField - try to layout all fields in the record decl. - /// Returns false if the operation failed because the struct is not packed. - bool LayoutFields(const RecordDecl *D); - - /// LayoutBases - layout the bases and vtable pointer of a record decl. - void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout); - - /// LayoutField - layout a single field. Returns false if the operation failed - /// because the current struct is not packed. - bool LayoutField(const FieldDecl *D, uint64_t FieldOffset); - - /// LayoutBitField - layout a single bit field. - void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset); - - /// AppendField - Appends a field with the given offset and type. - void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); - - /// AppendPadding - Appends enough padding bytes so that the total struct - /// size matches the alignment of the passed in type. - void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); - - /// AppendPadding - Appends enough padding bytes so that the total - /// struct size is a multiple of the field alignment. - void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment); - - /// AppendBytes - Append a given number of bytes to the record. - void AppendBytes(uint64_t NumBytes); - - /// AppendTailPadding - Append enough tail padding so that the type will have - /// the passed size. - void AppendTailPadding(uint64_t RecordSize); - - unsigned getTypeAlignment(const llvm::Type *Ty) const; - uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const; - - /// CheckForPointerToDataMember - Check if the given type contains a pointer - /// to data member. - void CheckForPointerToDataMember(QualType T); - -public: - /// ComputeLayout - Return the right record layout for a given record decl. - static CGRecordLayout *ComputeLayout(CodeGenTypes &Types, - const RecordDecl *D); -}; - -} // end namespace CodeGen -} // end namespace clang - - -#endif diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index a889e55..ae2f791 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -607,7 +607,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { } else if (FnRetTy->isReferenceType()) { // If this function returns a reference, take the address of the expression // rather than the value. - Builder.CreateStore(EmitLValue(RV).getAddress(), ReturnValue); + RValue Result = EmitReferenceBindingToExpr(RV, false); + Builder.CreateStore(Result.getScalarVal(), ReturnValue); } else if (!hasAggregateLLVMType(RV->getType())) { Builder.CreateStore(EmitScalarExpr(RV), ReturnValue); } else if (RV->getType()->isAnyComplexType()) { diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp index bed8439..6d38ab9 100644 --- a/lib/CodeGen/CGTemporaries.cpp +++ b/lib/CodeGen/CGTemporaries.cpp @@ -127,15 +127,14 @@ CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, size_t CleanupStackDepth = CleanupEntries.size(); (void) CleanupStackDepth; - unsigned OldNumLiveTemporaries = LiveTemporaries.size(); - - RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, - /*IgnoreResult=*/false, IsInitializer); - - // Pop temporaries. - while (LiveTemporaries.size() > OldNumLiveTemporaries) - PopCXXTemporary(); + RValue RV; + + { + CXXTemporariesCleanupScope Scope(*this); + RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, + /*IgnoreResult=*/false, IsInitializer); + } assert(CleanupEntries.size() == CleanupStackDepth && "Cleanup size mismatch!"); diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index 96c104b..91d9f76 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -19,283 +19,355 @@ using namespace CodeGen; #define D1(x) namespace { + +/// VTT builder - Class for building VTT layout information. class VTTBuilder { - /// Inits - The list of values built for the VTT. - std::vector<llvm::Constant *> &Inits; - /// Class - The most derived class that this vtable is being built for. - const CXXRecordDecl *Class; - CodeGenModule &CGM; // Per-module state. - llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase; - /// BLayout - Layout for the most derived class that this vtable is being - /// built for. - const ASTRecordLayout &BLayout; - CGVtableInfo::AddrMap_t &AddressPoints; - // vtbl - A pointer to the vtable for Class. - llvm::Constant *ClassVtbl; - llvm::LLVMContext &VMContext; - - /// SeenVBasesInSecondary - The seen virtual bases when building the - /// secondary virtual pointers. - llvm::SmallPtrSet<const CXXRecordDecl *, 32> SeenVBasesInSecondary; + + CodeGenModule &CGM; - llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies; + /// MostDerivedClass - The most derived class for which we're building this + /// vtable. + const CXXRecordDecl *MostDerivedClass; + + typedef llvm::SmallVector<llvm::Constant *, 64> VTTComponentsVectorTy; - bool GenerateDefinition; + /// VTTComponents - The VTT components. + VTTComponentsVectorTy VTTComponents; + + /// MostDerivedClassLayout - the AST record layout of the most derived class. + const ASTRecordLayout &MostDerivedClassLayout; + + typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; - llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables; - llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t> - CtorVtableAddressPoints; + typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; + + /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived + /// class. + llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies; + + /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of + /// all subobjects of the most derived class. + llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices; + + /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for + /// the VTT. + bool GenerateDefinition; - llvm::Constant *getCtorVtable(const BaseSubobject &Base, - bool BaseIsVirtual) { - if (!GenerateDefinition) - return 0; - - llvm::Constant *&CtorVtable = CtorVtables[Base]; - if (!CtorVtable) { - // Build the vtable. - CGVtableInfo::CtorVtableInfo Info - = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseIsVirtual); - - CtorVtable = Info.Vtable; - - // Add the address points for this base. - for (CGVtableInfo::AddressPointsMapTy::const_iterator I = - Info.AddressPoints.begin(), E = Info.AddressPoints.end(); - I != E; ++I) { - uint64_t &AddressPoint = - CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)]; - - // Check if we already have the address points for this base. - if (AddressPoint) - break; - - // Otherwise, insert it. - AddressPoint = I->second; - } - } - - return CtorVtable; + /// GetAddrOfVTable - Returns the address of the vtable for the base class in + /// the given vtable class. + /// + /// \param AddressPoints - If the returned vtable is a construction vtable, + /// this will hold the address points for it. + llvm::Constant *GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual, + AddressPointsMapTy& AddressPoints); + + /// AddVTablePointer - Add a vtable pointer to the VTT currently being built. + /// + /// \param AddressPoints - If the vtable is a construction vtable, this has + /// the address points for it. + void AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + const AddressPointsMapTy& AddressPoints); + + /// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base + /// subobject. + void LayoutSecondaryVTTs(BaseSubobject Base); + + /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers + /// for the given base subobject. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + /// + /// \param AddressPoints - If the vtable is a construction vtable, this has + /// the address points for it. + void LayoutSecondaryVirtualPointers(BaseSubobject Base, + bool BaseIsMorallyVirtual, + llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + const AddressPointsMapTy& AddressPoints, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers + /// for the given base subobject. + /// + /// \param AddressPoints - If the vtable is a construction vtable, this has + /// the address points for it. + void LayoutSecondaryVirtualPointers(BaseSubobject Base, + llvm::Constant *VTable, + const AddressPointsMapTy& AddressPoints); + + /// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the + /// given record decl. + void LayoutVirtualVTTs(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutVTT - Will lay out the VTT for the given subobject, including any + /// secondary VTTs, secondary virtual pointers and virtual VTTs. + void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual); + +public: + VTTBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerivedClass, + bool GenerateDefinition); + + // getVTTComponents - Returns a reference to the VTT components. + const VTTComponentsVectorTy &getVTTComponents() const { + return VTTComponents; } + /// getSubVTTIndicies - Returns a reference to the sub-VTT indices. + const llvm::DenseMap<const CXXRecordDecl *, uint64_t> & + getSubVTTIndicies() const { + return SubVTTIndicies; + } - /// BuildVtablePtr - Build up a referene to the given secondary vtable - llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable, - const CXXRecordDecl *VtableClass, - const CXXRecordDecl *RD, - uint64_t Offset) { - if (!GenerateDefinition) - return 0; - - uint64_t AddressPoint; - - if (VtableClass != Class) { - // We have a ctor vtable, look for the address point in the ctor vtable - // address points. - AddressPoint = - CtorVtableAddressPoints[std::make_pair(VtableClass, - BaseSubobject(RD, Offset))]; - } else { - AddressPoint = - (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)]; - } + /// getSecondaryVirtualPointerIndices - Returns a reference to the secondary + /// virtual pointer indices. + const llvm::DenseMap<BaseSubobject, uint64_t> & + getSecondaryVirtualPointerIndices() const { + return SecondaryVirtualPointerIndices; + } - // FIXME: We can never have 0 address point. Do this for now so gepping - // retains the same structure. Later we'll just assert. - if (AddressPoint == 0) - AddressPoint = 1; - D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n", - RD->getNameAsCString(), VtblClass->getNameAsCString(), - Class->getNameAsCString(), (int)Offset, (int)AddressPoint)); - - llvm::Value *Idxs[] = { - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0), - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint) - }; +}; + +VTTBuilder::VTTBuilder(CodeGenModule &CGM, + const CXXRecordDecl *MostDerivedClass, + bool GenerateDefinition) + : CGM(CGM), MostDerivedClass(MostDerivedClass), + MostDerivedClassLayout(CGM.getContext().getASTRecordLayout(MostDerivedClass)), + GenerateDefinition(GenerateDefinition) { - llvm::Constant *Init = - llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2); + // Lay out this VTT. + LayoutVTT(BaseSubobject(MostDerivedClass, 0), /*BaseIsVirtual=*/false); +} - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); +llvm::Constant * +VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual, + AddressPointsMapTy& AddressPoints) { + if (!GenerateDefinition) + return 0; + + if (Base.getBase() == MostDerivedClass) { + assert(Base.getBaseOffset() == 0 && + "Most derived class vtable must have a zero offset!"); + // This is a regular vtable. + return CGM.getVTables().GetAddrOfVTable(MostDerivedClass); } + + return CGM.getVTables().GenerateConstructionVTable(MostDerivedClass, + Base, BaseIsVirtual, + AddressPoints); +} - /// Secondary - Add the secondary vtable pointers to Inits. Offset is the - /// current offset in bits to the object we're working on. - void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl, - const CXXRecordDecl *VtblClass, uint64_t Offset=0, - bool MorallyVirtual=false) { - if (RD->getNumVBases() == 0 && ! MorallyVirtual) - return; - - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - - // We only want to visit each virtual base once. - if (i->isVirtual() && SeenVBasesInSecondary.count(Base)) - continue; - - // Itanium C++ ABI 2.6.2: - // Secondary virtual pointers are present for all bases with either - // virtual bases or virtual function declarations overridden along a - // virtual path. - // - // If the base class is not dynamic, we don't want to add it, nor any - // of its base classes. - if (!Base->isDynamicClass()) - continue; +void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + const AddressPointsMapTy& AddressPoints) { + // Store the vtable pointer index if we're generating the primary VTT. + if (VTableClass == MostDerivedClass) { + assert(!SecondaryVirtualPointerIndices.count(Base) && + "A virtual pointer index already exists for this base subobject!"); + SecondaryVirtualPointerIndices[Base] = VTTComponents.size(); + } - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - bool NonVirtualPrimaryBase; - NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase; - bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual(); - uint64_t BaseOffset; - if (!i->isVirtual()) { - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - BaseOffset = Offset + Layout.getBaseClassOffset(Base); - } else - BaseOffset = BLayout.getVBaseClassOffset(Base); - llvm::Constant *subvtbl = vtbl; - const CXXRecordDecl *subVtblClass = VtblClass; - if ((Base->getNumVBases() || BaseMorallyVirtual) - && !NonVirtualPrimaryBase) { - llvm::Constant *init; - if (BaseMorallyVirtual || VtblClass == Class) - init = BuildVtablePtr(vtbl, VtblClass, Base, BaseOffset); - else { - init = getCtorVtable(BaseSubobject(Base, BaseOffset), i->isVirtual()); - - subvtbl = init; - subVtblClass = Base; - - init = BuildVtablePtr(init, Class, Base, BaseOffset); - } - - Inits.push_back(init); - } - - if (i->isVirtual()) - SeenVBasesInSecondary.insert(Base); - - Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual); - } + if (!GenerateDefinition) { + VTTComponents.push_back(0); + return; } - /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the - /// currnet object we're working on. - void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool BaseIsVirtual, - bool MorallyVirtual) { - // Itanium C++ ABI 2.6.2: - // An array of virtual table addresses, called the VTT, is declared for - // each class type that has indirect or direct virtual base classes. - if (RD->getNumVBases() == 0) - return; + uint64_t AddressPoint; + if (VTableClass != MostDerivedClass) { + // The vtable is a construction vtable, look in the construction vtable + // address points. + AddressPoint = AddressPoints.lookup(Base); + } else { + // Just get the address point for the regular vtable. + AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass); + } - // Remember the sub-VTT index. - SubVTTIndicies[RD] = Inits.size(); + if (!AddressPoint) AddressPoint = 0; + assert(AddressPoint != 0 && "Did not find an address point!"); + + llvm::Value *Idxs[] = { + llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), + AddressPoint) + }; + + llvm::Constant *Init = + llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Idxs, 2); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); + + VTTComponents.push_back(Init); +} - llvm::Constant *Vtable; - const CXXRecordDecl *VtableClass; +void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { + const CXXRecordDecl *RD = Base.getBase(); - // First comes the primary virtual table pointer... - if (MorallyVirtual) { - Vtable = ClassVtbl; - VtableClass = Class; - } else { - Vtable = getCtorVtable(BaseSubobject(RD, Offset), - /*IsVirtual=*/BaseIsVirtual); - VtableClass = RD; - } + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { - llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset); - Inits.push_back(Init); - - // then the secondary VTTs.... - SecondaryVTTs(RD, Offset, MorallyVirtual); + // Don't layout virtual bases. + if (I->isVirtual()) + continue; - // Make sure to clear the set of seen virtual bases. - SeenVBasesInSecondary.clear(); + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - // and last the secondary vtable pointers. - Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + uint64_t BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + // Layout the VTT for this base. + LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false); } +} + +void +VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, + bool BaseIsMorallyVirtual, + llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + const AddressPointsMapTy& AddressPoints, + VisitedVirtualBasesSetTy &VBases) { + const CXXRecordDecl *RD = Base.getBase(); + + // We're not interested in bases that don't have virtual bases, and not + // morally virtual bases. + if (!RD->getNumVBases() && !BaseIsMorallyVirtual) + return; - /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are - /// built from each direct non-virtual proper base that requires a VTT in - /// declaration order. - void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0, - bool MorallyVirtual=false) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (i->isVirtual()) + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Itanium C++ ABI 2.6.2: + // Secondary virtual pointers are present for all bases with either + // virtual bases or virtual function declarations overridden along a + // virtual path. + // + // If the base class is not dynamic, we don't want to add it, nor any + // of its base classes. + if (!BaseDecl->isDynamicClass()) + continue; + + bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; + bool BaseDeclIsNonVirtualPrimaryBase = false; + uint64_t BaseOffset; + if (I->isVirtual()) { + // Ignore virtual bases that we've already visited. + if (!VBases.insert(BaseDecl)) continue; + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + BaseDeclIsMorallyVirtual = true; + } else { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base); - BuildVTT(Base, BaseOffset, /*BaseIsVirtual=*/false, MorallyVirtual); + BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); + + if (!Layout.getPrimaryBaseWasVirtual() && + Layout.getPrimaryBase() == BaseDecl) + BaseDeclIsNonVirtualPrimaryBase = true; } - } - /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance - /// graph preorder. - void VirtualVTTs(const CXXRecordDecl *RD) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (i->isVirtual() && !SeenVBase.count(Base)) { - SeenVBase.insert(Base); - uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base); - BuildVTT(Base, BaseOffset, /*BaseIsVirtual=*/true, false); - } - VirtualVTTs(Base); + // Itanium C++ ABI 2.6.2: + // Secondary virtual pointers: for each base class X which (a) has virtual + // bases or is reachable along a virtual path from D, and (b) is not a + // non-virtual primary base, the address of the virtual table for X-in-D + // or an appropriate construction virtual table. + if (!BaseDeclIsNonVirtualPrimaryBase && + (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) { + // Add the vtable pointer. + AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable, VTableClass, + AddressPoints); } + + // And lay out the secondary virtual pointers for the base class. + LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset), + BaseDeclIsMorallyVirtual, VTable, + VTableClass, AddressPoints, VBases); } +} -public: - VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c, - CodeGenModule &cgm, bool GenerateDefinition) - : Inits(inits), Class(c), CGM(cgm), - BLayout(cgm.getContext().getASTRecordLayout(c)), - AddressPoints(*cgm.getVtableInfo().AddressPoints[c]), - VMContext(cgm.getModule().getContext()), - GenerateDefinition(GenerateDefinition) { - - // First comes the primary virtual table pointer for the complete class... - ClassVtbl = GenerateDefinition ? CGM.getVtableInfo().getVtable(Class) : 0; +void +VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, + llvm::Constant *VTable, + const AddressPointsMapTy& AddressPoints) { + VisitedVirtualBasesSetTy VBases; + LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false, + VTable, Base.getBase(), AddressPoints, VBases); +} - llvm::Constant *Init = BuildVtablePtr(ClassVtbl, Class, Class, 0); - Inits.push_back(Init); +void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases) { + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - // then the secondary VTTs... - SecondaryVTTs(Class); + // Check if this is a virtual base. + if (I->isVirtual()) { + // Check if we've seen this base before. + if (!VBases.insert(BaseDecl)) + continue; + + uint64_t BaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + + LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true); + } + + // We only need to layout virtual VTTs for this base if it actually has + // virtual bases. + if (BaseDecl->getNumVBases()) + LayoutVirtualVTTs(BaseDecl, VBases); + } +} - // Make sure to clear the set of seen virtual bases. - SeenVBasesInSecondary.clear(); +void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) { + const CXXRecordDecl *RD = Base.getBase(); - // then the secondary vtable pointers... - Secondary(Class, ClassVtbl, Class); + // Itanium C++ ABI 2.6.2: + // An array of virtual table addresses, called the VTT, is declared for + // each class type that has indirect or direct virtual base classes. + if (RD->getNumVBases() == 0) + return; + + bool IsPrimaryVTT = Base.getBase() == MostDerivedClass; - // and last, the virtual VTTs. - VirtualVTTs(Class); + if (!IsPrimaryVTT) { + // Remember the sub-VTT index. + SubVTTIndicies[RD] = VTTComponents.size(); } + + AddressPointsMapTy AddressPoints; + llvm::Constant *VTable = GetAddrOfVTable(Base, BaseIsVirtual, AddressPoints); + + // Add the primary vtable pointer. + AddVTablePointer(Base, VTable, RD, AddressPoints); + + // Add the secondary VTTs. + LayoutSecondaryVTTs(Base); - llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() { - return SubVTTIndicies; + // Add the secondary virtual pointers. + LayoutSecondaryVirtualPointers(Base, VTable, AddressPoints); + + // If this is the primary VTT, we want to lay out virtual VTTs as well. + if (IsPrimaryVTT) { + VisitedVirtualBasesSetTy VBases; + LayoutVirtualVTTs(Base.getBase(), VBases); } -}; +} + } llvm::GlobalVariable * -CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, - bool GenerateDefinition, - const CXXRecordDecl *RD) { +CodeGenVTables::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, + const CXXRecordDecl *RD) { // Only classes that have virtual bases need a VTT. if (RD->getNumVBases() == 0) return 0; @@ -311,13 +383,15 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - std::vector<llvm::Constant *> inits; - VTTBuilder b(inits, RD, CGM, GenerateDefinition); + VTTBuilder Builder(CGM, RD, GenerateDefinition); + + const llvm::ArrayType *Type = + llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size()); - const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size()); llvm::Constant *Init = 0; if (GenerateDefinition) - Init = llvm::ConstantArray::get(Type, inits); + Init = llvm::ConstantArray::get(Type, Builder.getVTTComponents().data(), + Builder.getVTTComponents().size()); llvm::GlobalVariable *OldGV = GV; GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, @@ -336,26 +410,12 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, return GV; } -CGVtableInfo::CtorVtableInfo -CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD, - const BaseSubobject &Base, bool BaseIsVirtual) { - CtorVtableInfo Info; - - Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage, - /*GenerateDefinition=*/true, - RD, Base.getBase(), Base.getBaseOffset(), - BaseIsVirtual, Info.AddressPoints); - return Info; -} - -llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) { +llvm::GlobalVariable *CodeGenVTables::getVTT(const CXXRecordDecl *RD) { return GenerateVTT(llvm::GlobalValue::ExternalLinkage, /*GenerateDefinition=*/false, RD); - } - -bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) { +bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); // We don't have any virtual bases, just return early. @@ -373,19 +433,17 @@ bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) { return false; } -uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD, - const CXXRecordDecl *Base) { +uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD, + const CXXRecordDecl *Base) { ClassPairTy ClassPair(RD, Base); - SubVTTIndiciesTy::iterator I = - SubVTTIndicies.find(ClassPair); + SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassPair); if (I != SubVTTIndicies.end()) return I->second; - std::vector<llvm::Constant *> inits; - VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false); + VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); - for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = + for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::const_iterator I = Builder.getSubVTTIndicies().begin(), E = Builder.getSubVTTIndicies().end(); I != E; ++I) { // Insert all indices. @@ -399,3 +457,31 @@ uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD, return I->second; } + +uint64_t +CodeGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, + BaseSubobject Base) { + SecondaryVirtualPointerIndicesMapTy::iterator I = + SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base)); + + if (I != SecondaryVirtualPointerIndices.end()) + return I->second; + + VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); + + // Insert all secondary vpointer indices. + for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I = + Builder.getSecondaryVirtualPointerIndices().begin(), + E = Builder.getSecondaryVirtualPointerIndices().end(); I != E; ++I) { + std::pair<const CXXRecordDecl *, BaseSubobject> Pair = + std::make_pair(RD, I->first); + + SecondaryVirtualPointerIndices.insert(std::make_pair(Pair, I->second)); + } + + I = SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base)); + assert(I != SecondaryVirtualPointerIndices.end() && "Did not find index!"); + + return I->second; +} + diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index df30f47..2d1c734 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -138,7 +138,7 @@ private: /// AddOverriders - Add the final overriders for this base subobject to the /// map of final overriders. - void AddOverriders(BaseSubobject Base,uint64_t OffsetInLayoutClass, + void AddOverriders(BaseSubobject Base, uint64_t OffsetInLayoutClass, SubobjectOffsetsMapTy &Offsets); /// PropagateOverrider - Propagate the NewMD overrider to all the functions @@ -636,6 +636,10 @@ public: reinterpret_cast<uintptr_t>(MD)); } + static VtableComponent getFromOpaqueInteger(uint64_t I) { + return VtableComponent(I); + } + /// getKind - Get the kind of this vtable component. Kind getKind() const { return (Kind)(Value & 0x7); @@ -725,6 +729,9 @@ private: return static_cast<uintptr_t>(Value & ~7ULL); } + explicit VtableComponent(uint64_t Value) + : Value(Value) { } + /// The kind is stored in the lower 3 bits of the value. For offsets, we /// make use of the facts that classes can't be larger than 2^55 bytes, /// so we store the offset in the lower part of the 61 bytes that remain. @@ -1091,9 +1098,15 @@ public: typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> PrimaryBasesSetVectorTy; + typedef llvm::DenseMap<const CXXRecordDecl *, int64_t> + VBaseOffsetOffsetsMapTy; + + typedef llvm::DenseMap<BaseSubobject, uint64_t> + AddressPointsMapTy; + private: - /// VtableInfo - Global vtable information. - CGVtableInfo &VtableInfo; + /// VTables - Global vtable information. + CodeGenVTables &VTables; /// MostDerivedClass - The most derived class for which we're building this /// vtable. @@ -1122,9 +1135,6 @@ private: /// bases in this vtable. llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases; - typedef llvm::DenseMap<const CXXRecordDecl *, int64_t> - VBaseOffsetOffsetsMapTy; - /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for /// the most derived class. VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; @@ -1133,29 +1143,8 @@ private: llvm::SmallVector<VtableComponent, 64> Components; /// AddressPoints - Address points for the vtable being built. - CGVtableInfo::AddressPointsMapTy AddressPoints; - - /// ReturnAdjustment - A return adjustment. - struct ReturnAdjustment { - /// NonVirtual - The non-virtual adjustment from the derived object to its - /// nearest virtual base. - int64_t NonVirtual; - - /// VBaseOffsetOffset - The offset (in bytes), relative to the address point - /// of the virtual base class offset. - int64_t VBaseOffsetOffset; - - ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { } - - bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } + AddressPointsMapTy AddressPoints; - friend bool operator==(const ReturnAdjustment &LHS, - const ReturnAdjustment &RHS) { - return LHS.NonVirtual == RHS.NonVirtual && - LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset; - } - }; - /// MethodInfo - Contains information about a method in a vtable. /// (Used for computing 'this' pointer adjustment thunks. struct MethodInfo { @@ -1185,62 +1174,21 @@ private: /// currently building. MethodInfoMapTy MethodInfoMap; - /// ThisAdjustment - A 'this' pointer adjustment thunk. - struct ThisAdjustment { - /// NonVirtual - The non-virtual adjustment from the derived object to its - /// nearest virtual base. - int64_t NonVirtual; - - /// VCallOffsetOffset - The offset (in bytes), relative to the address point, - /// of the virtual call offset. - int64_t VCallOffsetOffset; - - ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { } - - bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } - - friend bool operator==(const ThisAdjustment &LHS, - const ThisAdjustment &RHS) { - return LHS.NonVirtual == RHS.NonVirtual && - LHS.VCallOffsetOffset == RHS.VCallOffsetOffset; - } - }; - - /// ThunkInfo - The 'this' pointer adjustment as well as an optional return - /// adjustment for a thunk. - struct ThunkInfo { - /// This - The 'this' pointer adjustment. - ThisAdjustment This; - - /// Return - The return adjustment. - ReturnAdjustment Return; - - ThunkInfo() { } - - ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return) - : This(This), Return(Return) { } + typedef llvm::DenseMap<uint64_t, ThunkInfo> VtableThunksMapTy; - friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { - return LHS.This == RHS.This && LHS.Return == RHS.Return; - } + /// VTableThunks - The thunks by vtable index in the vtable currently being + /// built. + VtableThunksMapTy VTableThunks; - bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); } - }; - - typedef llvm::DenseMap<uint64_t, ThunkInfo> ThunksInfoMapTy; + typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; + typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; - /// Thunks - The thunks by vtable index in the vtable currently being built. - ThunksInfoMapTy Thunks; - - typedef llvm::DenseMap<const CXXMethodDecl *, - llvm::SmallVector<ThunkInfo, 1> > MethodThunksMapTy; - - /// MethodThunks - A map that contains all the thunks needed for all methods - /// in the vtable currently being built. - MethodThunksMapTy MethodThunks; + /// Thunks - A map that contains all the thunks needed for all methods in the + /// most derived class for which the vtable is currently being built. + ThunksMapTy Thunks; /// AddThunk - Add a thunk for the given method. - void AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk); + void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk); /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the /// part of the vtable we're currently building. @@ -1341,10 +1289,10 @@ private: } public: - VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass, + VtableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass, uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) - : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass), + : VTables(VTables), MostDerivedClass(MostDerivedClass), MostDerivedClassOffset(MostDerivedClassOffset), MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), @@ -1353,15 +1301,57 @@ public: LayoutVtable(); } + ThunksMapTy::const_iterator thunks_begin() const { + return Thunks.begin(); + } + + ThunksMapTy::const_iterator thunks_end() const { + return Thunks.end(); + } + + const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { + return VBaseOffsetOffsets; + } + + /// getNumVTableComponents - Return the number of components in the vtable + /// currently built. + uint64_t getNumVTableComponents() const { + return Components.size(); + } + + const uint64_t *vtable_components_data_begin() const { + return reinterpret_cast<const uint64_t *>(Components.begin()); + } + + const uint64_t *vtable_components_data_end() const { + return reinterpret_cast<const uint64_t *>(Components.end()); + } + + AddressPointsMapTy::const_iterator address_points_begin() const { + return AddressPoints.begin(); + } + + AddressPointsMapTy::const_iterator address_points_end() const { + return AddressPoints.end(); + } + + VtableThunksMapTy::const_iterator vtable_thunks_begin() const { + return VTableThunks.begin(); + } + + VtableThunksMapTy::const_iterator vtable_thunks_end() const { + return VTableThunks.end(); + } + /// dumpLayout - Dump the vtable layout. void dumpLayout(llvm::raw_ostream&); }; -void VtableBuilder::AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk) { - if (isBuildingConstructorVtable()) - return; +void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { + assert(!isBuildingConstructorVtable() && + "Can't add thunks for construction vtable"); - llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD]; + llvm::SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD]; // Check if we have this thunk already. if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != @@ -1410,6 +1400,17 @@ void VtableBuilder::ComputeThisAdjustments() { Overriders.getOverrider(BaseSubobject(MD->getParent(), MethodInfo.BaseOffset), MD); + // Check if we need an adjustment at all. + if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) { + // When a return thunk is needed by a derived class that overrides a + // virtual base, gcc uses a virtual 'this' adjustment as well. + // While the thunk itself might be needed by vtables in subclasses or + // in construction vtables, there doesn't seem to be a reason for using + // the thunk in this vtable. Still, we do so to match gcc. + if (VTableThunks.lookup(VtableIndex).Return.isEmpty()) + continue; + } + ThisAdjustment ThisAdjustment = ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider); @@ -1417,22 +1418,48 @@ void VtableBuilder::ComputeThisAdjustments() { continue; // Add it. - Thunks[VtableIndex].This = ThisAdjustment; + VTableThunks[VtableIndex].This = ThisAdjustment; if (isa<CXXDestructorDecl>(MD)) { // Add an adjustment for the deleting destructor as well. - Thunks[VtableIndex + 1].This = ThisAdjustment; + VTableThunks[VtableIndex + 1].This = ThisAdjustment; } - - AddThunk(Overrider.Method, Thunks[VtableIndex]); } /// Clear the method info map. MethodInfoMap.clear(); + + if (isBuildingConstructorVtable()) { + // We don't need to store thunk information for construction vtables. + return; + } + + for (VtableThunksMapTy::const_iterator I = VTableThunks.begin(), + E = VTableThunks.end(); I != E; ++I) { + const VtableComponent &Component = Components[I->first]; + const ThunkInfo &Thunk = I->second; + const CXXMethodDecl *MD; + + switch (Component.getKind()) { + default: + llvm_unreachable("Unexpected vtable component kind!"); + case VtableComponent::CK_FunctionPointer: + MD = Component.getFunctionDecl(); + break; + case VtableComponent::CK_CompleteDtorPointer: + MD = Component.getDestructorDecl(); + break; + case VtableComponent::CK_DeletingDtorPointer: + // We've already added the thunk when we saw the complete dtor pointer. + continue; + } + + if (MD->getParent() == MostDerivedClass) + AddThunk(MD, Thunk); + } } -VtableBuilder::ReturnAdjustment -VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { +ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { ReturnAdjustment Adjustment; if (!Offset.isEmpty()) { @@ -1444,8 +1471,8 @@ VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { VBaseOffsetOffsets.lookup(Offset.VirtualBase); } else { Adjustment.VBaseOffsetOffset = - VtableInfo.getVirtualBaseOffsetOffset(Offset.DerivedClass, - Offset.VirtualBase); + VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, + Offset.VirtualBase); } // FIXME: Once the assert in getVirtualBaseOffsetOffset is back again, @@ -1512,14 +1539,10 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, return BaseOffset(); } -VtableBuilder::ThisAdjustment +ThisAdjustment VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, uint64_t BaseOffsetInLayoutClass, FinalOverriders::OverriderInfo Overrider) { - // Check if we need an adjustment at all. - if (BaseOffsetInLayoutClass == Overrider.Offset) - return ThisAdjustment(); - // Ignore adjustments for pure virtual member functions. if (Overrider.Method->isPure()) return ThisAdjustment(); @@ -1576,7 +1599,7 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD, } else { // Add the return adjustment if necessary. if (!ReturnAdjustment.isEmpty()) - Thunks[Components.size()].Return = ReturnAdjustment; + VTableThunks[Components.size()].Return = ReturnAdjustment; // Add the function. Components.push_back(VtableComponent::MakeFunction(MD)); @@ -1776,6 +1799,25 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); MethodInfoMap.erase(OverriddenMD); + + // If the overridden method exists in a virtual base class or a direct + // or indirect base class of a virtual base class, we need to emit a + // thunk if we ever have a class hierarchy where the base class is not + // a primary base in the complete object. + if (!isBuildingConstructorVtable() && OverriddenMD != MD) { + // Compute the this adjustment. + ThisAdjustment ThisAdjustment = + ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, + Overrider); + + if (ThisAdjustment.VCallOffsetOffset && + Overrider.Method->getParent() == MostDerivedClass) { + // This is a virtual thunk for the most derived class, add it. + AddThunk(Overrider.Method, + ThunkInfo(ThisAdjustment, ReturnAdjustment())); + } + } + continue; } } @@ -1866,20 +1908,32 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, // Compute 'this' pointer adjustments. ComputeThisAdjustments(); - // Record the address point. - AddressPoints.insert(std::make_pair(BaseSubobject(Base.getBase(), - OffsetInLayoutClass), - AddressPoint)); - - // Record the address points for all primary bases. - for (PrimaryBasesSetVectorTy::const_iterator I = PrimaryBases.begin(), - E = PrimaryBases.end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = *I; + // Add all address points. + const CXXRecordDecl *RD = Base.getBase(); + while (true) { + AddressPoints.insert(std::make_pair(BaseSubobject(RD, OffsetInLayoutClass), + AddressPoint)); + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - // We know that all the primary bases have the same offset as the base - // subobject. - BaseSubobject PrimaryBase(BaseDecl, OffsetInLayoutClass); - AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint)); + if (!PrimaryBase) + break; + + if (Layout.getPrimaryBaseWasVirtual()) { + // Check if this virtual primary base is a primary base in the layout + // class. If it's not, we don't want to add it. + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != + OffsetInLayoutClass) { + // We don't want to add this class (or any of its primary bases). + break; + } + } + + RD = PrimaryBase; } bool BaseIsMorallyVirtual = BaseIsVirtual; @@ -2062,8 +2116,8 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { // Since an address point can be shared by multiple subobjects, we use an // STL multimap. std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex; - for (CGVtableInfo::AddressPointsMapTy::const_iterator I = - AddressPoints.begin(), E = AddressPoints.end(); I != E; ++I) { + for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(), + E = AddressPoints.end(); I != E; ++I) { const BaseSubobject& Base = I->first; uint64_t Index = I->second; @@ -2106,7 +2160,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { if (MD->isPure()) Out << " [pure]"; - ThunkInfo Thunk = Thunks.lookup(I); + ThunkInfo Thunk = VTableThunks.lookup(I); if (!Thunk.isEmpty()) { // If this function pointer has a return adjustment, dump it. if (!Thunk.Return.isEmpty()) { @@ -2154,7 +2208,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { if (DD->isPure()) Out << " [pure]"; - ThunkInfo Thunk = Thunks.lookup(I); + ThunkInfo Thunk = VTableThunks.lookup(I); if (!Thunk.isEmpty()) { // If this destructor has a 'this' pointer adjustment, dump it. if (!Thunk.This.isEmpty()) { @@ -2253,13 +2307,12 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { Out << "\n"; } - if (!MethodThunks.empty()) { - + if (!Thunks.empty()) { // We store the method names in a map to get a stable order. std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls; - for (MethodThunksMapTy::const_iterator I = MethodThunks.begin(), - E = MethodThunks.end(); I != E; ++I) { + for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end(); + I != E; ++I) { const CXXMethodDecl *MD = I->first; std::string MethodName = PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, @@ -2273,7 +2326,9 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { I != E; ++I) { const std::string &MethodName = I->first; const CXXMethodDecl *MD = I->second; - const llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD]; + + ThunkInfoVectorTy ThunksVector = Thunks[MD]; + std::sort(ThunksVector.begin(), ThunksVector.end()); Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; @@ -2283,1099 +2338,42 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { Out << llvm::format("%4d | ", I); + // If this function pointer has a return pointer adjustment, dump it. + if (!Thunk.Return.isEmpty()) { + Out << "return adjustment: " << Thunk.This.NonVirtual; + Out << " non-virtual"; + if (Thunk.Return.VBaseOffsetOffset) { + Out << ", " << Thunk.Return.VBaseOffsetOffset; + Out << " vbase offset offset"; + } + + if (!Thunk.This.isEmpty()) + Out << "\n "; + } + // If this function pointer has a 'this' pointer adjustment, dump it. if (!Thunk.This.isEmpty()) { - Out << "this: "; - Out << Thunk.This.NonVirtual << " nv"; + Out << "this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; if (Thunk.This.VCallOffsetOffset) { Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " v"; + Out << " vcall offset offset"; } } Out << '\n'; } - } - } -} - -} - -namespace { -class OldVtableBuilder { -public: - /// Index_t - Vtable index type. - typedef uint64_t Index_t; - typedef std::vector<std::pair<GlobalDecl, - std::pair<GlobalDecl, ThunkAdjustment> > > - SavedAdjustmentsVectorTy; -private: - - // VtableComponents - The components of the vtable being built. - typedef llvm::SmallVector<llvm::Constant *, 64> VtableComponentsVectorTy; - VtableComponentsVectorTy VtableComponents; - - const bool BuildVtable; - - llvm::Type *Ptr8Ty; - - /// MostDerivedClass - The most derived class that this vtable is being - /// built for. - const CXXRecordDecl *MostDerivedClass; - - /// LayoutClass - The most derived class used for virtual base layout - /// information. - const CXXRecordDecl *LayoutClass; - /// LayoutOffset - The offset for Class in LayoutClass. - uint64_t LayoutOffset; - /// BLayout - Layout for the most derived class that this vtable is being - /// built for. - const ASTRecordLayout &BLayout; - llvm::SmallSet<const CXXRecordDecl *, 32> IndirectPrimary; - llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase; - llvm::Constant *rtti; - llvm::LLVMContext &VMContext; - CodeGenModule &CGM; // Per-module state. - - llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall; - llvm::DenseMap<GlobalDecl, Index_t> VCallOffset; - llvm::DenseMap<GlobalDecl, Index_t> VCallOffsetForVCall; - // This is the offset to the nearest virtual base - llvm::DenseMap<const CXXMethodDecl *, Index_t> NonVirtualOffset; - llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex; - - /// PureVirtualFunction - Points to __cxa_pure_virtual. - llvm::Constant *PureVirtualFn; - - /// VtableMethods - A data structure for keeping track of methods in a vtable. - /// Can add methods, override methods and iterate in vtable order. - class VtableMethods { - // MethodToIndexMap - Maps from a global decl to the index it has in the - // Methods vector. - llvm::DenseMap<GlobalDecl, uint64_t> MethodToIndexMap; - - /// Methods - The methods, in vtable order. - typedef llvm::SmallVector<GlobalDecl, 16> MethodsVectorTy; - MethodsVectorTy Methods; - MethodsVectorTy OrigMethods; - - public: - /// AddMethod - Add a method to the vtable methods. - void AddMethod(GlobalDecl GD) { - assert(!MethodToIndexMap.count(GD) && - "Method has already been added!"); - - MethodToIndexMap[GD] = Methods.size(); - Methods.push_back(GD); - OrigMethods.push_back(GD); - } - - /// OverrideMethod - Replace a method with another. - void OverrideMethod(GlobalDecl OverriddenGD, GlobalDecl GD) { - llvm::DenseMap<GlobalDecl, uint64_t>::iterator i - = MethodToIndexMap.find(OverriddenGD); - assert(i != MethodToIndexMap.end() && "Did not find entry!"); - - // Get the index of the old decl. - uint64_t Index = i->second; - - // Replace the old decl with the new decl. - Methods[Index] = GD; - - // And add the new. - MethodToIndexMap[GD] = Index; - } - - /// getIndex - Gives the index of a passed in GlobalDecl. Returns false if - /// the index couldn't be found. - bool getIndex(GlobalDecl GD, uint64_t &Index) const { - llvm::DenseMap<GlobalDecl, uint64_t>::const_iterator i - = MethodToIndexMap.find(GD); - - if (i == MethodToIndexMap.end()) - return false; - - Index = i->second; - return true; - } - - GlobalDecl getOrigMethod(uint64_t Index) const { - return OrigMethods[Index]; - } - - MethodsVectorTy::size_type size() const { - return Methods.size(); - } - - void clear() { - MethodToIndexMap.clear(); - Methods.clear(); - OrigMethods.clear(); - } - - GlobalDecl operator[](uint64_t Index) const { - return Methods[Index]; - } - }; - - /// Methods - The vtable methods we're currently building. - VtableMethods Methods; - - /// ThisAdjustments - For a given index in the vtable, contains the 'this' - /// pointer adjustment needed for a method. - typedef llvm::DenseMap<uint64_t, ThunkAdjustment> ThisAdjustmentsMapTy; - ThisAdjustmentsMapTy ThisAdjustments; - - SavedAdjustmentsVectorTy SavedAdjustments; - - /// BaseReturnTypes - Contains the base return types of methods who have been - /// overridden with methods whose return types require adjustment. Used for - /// generating covariant thunk information. - typedef llvm::DenseMap<uint64_t, CanQualType> BaseReturnTypesMapTy; - BaseReturnTypesMapTy BaseReturnTypes; - - std::vector<Index_t> VCalls; - - typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; - // subAddressPoints - Used to hold the AddressPoints (offsets) into the built - // vtable for use in computing the initializers for the VTT. - llvm::DenseMap<CtorVtable_t, int64_t> &subAddressPoints; - - /// AddressPoints - Address points for this vtable. - CGVtableInfo::AddressPointsMapTy& AddressPoints; - - typedef CXXRecordDecl::method_iterator method_iter; - const uint32_t LLVMPointerWidth; - Index_t extra; - typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t; - static llvm::DenseMap<CtorVtable_t, int64_t>& - AllocAddressPoint(CodeGenModule &cgm, const CXXRecordDecl *l, - const CXXRecordDecl *c) { - CGVtableInfo::AddrMap_t *&oref = cgm.getVtableInfo().AddressPoints[l]; - if (oref == 0) - oref = new CGVtableInfo::AddrMap_t; - - llvm::DenseMap<CtorVtable_t, int64_t> *&ref = (*oref)[c]; - if (ref == 0) - ref = new llvm::DenseMap<CtorVtable_t, int64_t>; - return *ref; - } - - bool DclIsSame(const FunctionDecl *New, const FunctionDecl *Old) { - FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate(); - FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate(); - - // C++ [temp.fct]p2: - // A function template can be overloaded with other function templates - // and with normal (non-template) functions. - if ((OldTemplate == 0) != (NewTemplate == 0)) - return false; - - // Is the function New an overload of the function Old? - QualType OldQType = CGM.getContext().getCanonicalType(Old->getType()); - QualType NewQType = CGM.getContext().getCanonicalType(New->getType()); - - // Compare the signatures (C++ 1.3.10) of the two functions to - // determine whether they are overloads. If we find any mismatch - // in the signature, they are overloads. - - // If either of these functions is a K&R-style function (no - // prototype), then we consider them to have matching signatures. - if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) || - isa<FunctionNoProtoType>(NewQType.getTypePtr())) - return true; - - FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType); - FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType); - - // The signature of a function includes the types of its - // parameters (C++ 1.3.10), which includes the presence or absence - // of the ellipsis; see C++ DR 357). - if (OldQType != NewQType && - (OldType->getNumArgs() != NewType->getNumArgs() || - OldType->isVariadic() != NewType->isVariadic() || - !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), - NewType->arg_type_begin()))) - return false; - -#if 0 - // C++ [temp.over.link]p4: - // The signature of a function template consists of its function - // signature, its return type and its template parameter list. The names - // of the template parameters are significant only for establishing the - // relationship between the template parameters and the rest of the - // signature. - // - // We check the return type and template parameter lists for function - // templates first; the remaining checks follow. - if (NewTemplate && - (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), - OldTemplate->getTemplateParameters(), - TPL_TemplateMatch) || - OldType->getResultType() != NewType->getResultType())) - return false; -#endif - - // If the function is a class member, its signature includes the - // cv-qualifiers (if any) on the function itself. - // - // As part of this, also check whether one of the member functions - // is static, in which case they are not overloads (C++ - // 13.1p2). While not part of the definition of the signature, - // this check is important to determine whether these functions - // can be overloaded. - const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); - const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); - if (OldMethod && NewMethod && - !OldMethod->isStatic() && !NewMethod->isStatic() && - OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers()) - return false; - - // The signatures match; this is not an overload. - return true; - } - - typedef llvm::DenseMap<const CXXMethodDecl *, const CXXMethodDecl*> - ForwardUnique_t; - ForwardUnique_t ForwardUnique; - llvm::DenseMap<const CXXMethodDecl*, const CXXMethodDecl*> UniqueOverrider; - - void BuildUniqueOverrider(const CXXMethodDecl *U, const CXXMethodDecl *MD) { - const CXXMethodDecl *PrevU = UniqueOverrider[MD]; - assert(U && "no unique overrider"); - if (PrevU == U) - return; - if (PrevU != U && PrevU != 0) { - // If already set, note the two sets as the same - if (0) - printf("%s::%s same as %s::%s\n", - PrevU->getParent()->getNameAsString().c_str(), - PrevU->getNameAsString().c_str(), - U->getParent()->getNameAsString().c_str(), - U->getNameAsString().c_str()); - ForwardUnique[PrevU] = U; - return; - } - - // Not set, set it now - if (0) - printf("marking %s::%s %p override as %s::%s\n", - MD->getParent()->getNameAsString().c_str(), - MD->getNameAsString().c_str(), - (void*)MD, - U->getParent()->getNameAsString().c_str(), - U->getNameAsString().c_str()); - UniqueOverrider[MD] = U; - - for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(), - me = MD->end_overridden_methods(); mi != me; ++mi) { - BuildUniqueOverrider(U, *mi); - } - } - - void BuildUniqueOverriders(const CXXRecordDecl *RD) { - if (0) printf("walking %s\n", RD->getNameAsCString()); - for (CXXRecordDecl::method_iterator i = RD->method_begin(), - e = RD->method_end(); i != e; ++i) { - const CXXMethodDecl *MD = *i; - if (!MD->isVirtual()) - continue; - - if (UniqueOverrider[MD] == 0) { - // Only set this, if it hasn't been set yet. - BuildUniqueOverrider(MD, MD); - if (0) - printf("top set is %s::%s %p\n", - MD->getParent()->getNameAsString().c_str(), - MD->getNameAsString().c_str(), - (void*)MD); - ForwardUnique[MD] = MD; - } - } - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - BuildUniqueOverriders(Base); - } - } - - static int DclCmp(const void *p1, const void *p2) { - const CXXMethodDecl *MD1 = *(const CXXMethodDecl *const *)p1; - const CXXMethodDecl *MD2 = *(const CXXMethodDecl *const *)p2; - - return (DeclarationName::compare(MD1->getDeclName(), MD2->getDeclName())); - } - - void MergeForwarding() { - typedef llvm::SmallVector<const CXXMethodDecl *, 100> A_t; - A_t A; - for (ForwardUnique_t::iterator I = ForwardUnique.begin(), - E = ForwardUnique.end(); I != E; ++I) { - if (I->first == I->second) - // Only add the roots of all trees - A.push_back(I->first); - } - llvm::array_pod_sort(A.begin(), A.end(), DclCmp); - for (A_t::iterator I = A.begin(), - E = A.end(); I != E; ++I) { - A_t::iterator J = I; - while (++J != E && DclCmp(I, J) == 0) - if (DclIsSame(*I, *J)) { - if (0) printf("connecting %s\n", (*I)->getNameAsString().c_str()); - ForwardUnique[*J] = *I; - } - } - } - - const CXXMethodDecl *getUnique(const CXXMethodDecl *MD) { - const CXXMethodDecl *U = UniqueOverrider[MD]; - assert(U && "unique overrider not found"); - while (ForwardUnique.count(U)) { - const CXXMethodDecl *NU = ForwardUnique[U]; - if (NU == U) break; - U = NU; - } - return U; - } - - GlobalDecl getUnique(GlobalDecl GD) { - const CXXMethodDecl *Unique = getUnique(cast<CXXMethodDecl>(GD.getDecl())); - - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Unique)) - return GlobalDecl(CD, GD.getCtorType()); - - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(Unique)) - return GlobalDecl(DD, GD.getDtorType()); - - return Unique; - } - - /// getPureVirtualFn - Return the __cxa_pure_virtual function. - llvm::Constant* getPureVirtualFn() { - if (!PureVirtualFn) { - const llvm::FunctionType *Ty = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - /*isVarArg=*/false); - PureVirtualFn = wrap(CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual")); - } - - return PureVirtualFn; - } - -public: - OldVtableBuilder(const CXXRecordDecl *MostDerivedClass, - const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm, - bool build, CGVtableInfo::AddressPointsMapTy& AddressPoints) - : BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l), - LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)), - rtti(0), VMContext(cgm.getModule().getContext()),CGM(cgm), - PureVirtualFn(0), - subAddressPoints(AllocAddressPoint(cgm, l, MostDerivedClass)), - AddressPoints(AddressPoints), - LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) - { - Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - if (BuildVtable) { - QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass); - rtti = CGM.GetAddrOfRTTIDescriptor(ClassType); - } - BuildUniqueOverriders(MostDerivedClass); - MergeForwarding(); - } - - // getVtableComponents - Returns a reference to the vtable components. - const VtableComponentsVectorTy &getVtableComponents() const { - return VtableComponents; - } - - llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getVBIndex() - { return VBIndex; } - - SavedAdjustmentsVectorTy &getSavedAdjustments() - { return SavedAdjustments; } - - llvm::Constant *wrap(Index_t i) { - llvm::Constant *m; - m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i); - return llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty); - } - - llvm::Constant *wrap(llvm::Constant *m) { - return llvm::ConstantExpr::getBitCast(m, Ptr8Ty); - } - -//#define D1(x) -#define D1(X) do { if (getenv("CLANG_VTABLE_DEBUG")) { X; } } while (0) - - void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, - bool updateVBIndex, Index_t current_vbindex) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - Index_t next_vbindex = current_vbindex; - if (i->isVirtual() && !SeenVBase.count(Base)) { - SeenVBase.insert(Base); - if (updateVBIndex) { - next_vbindex = (ssize_t)(-(VCalls.size()*LLVMPointerWidth/8) - - 3*LLVMPointerWidth/8); - VBIndex[Base] = next_vbindex; - } - int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8; - VCalls.push_back((0?700:0) + BaseOffset); - D1(printf(" vbase for %s at %d delta %d most derived %s\n", - Base->getNameAsCString(), - (int)-VCalls.size()-3, (int)BaseOffset, - MostDerivedClass->getNameAsCString())); - } - // We also record offsets for non-virtual bases to closest enclosing - // virtual base. We do this so that we don't have to search - // for the nearst virtual base class when generating thunks. - if (updateVBIndex && VBIndex.count(Base) == 0) - VBIndex[Base] = next_vbindex; - GenerateVBaseOffsets(Base, Offset, updateVBIndex, next_vbindex); - } - } - - void StartNewTable() { - SeenVBase.clear(); - } - - Index_t getNVOffset_1(const CXXRecordDecl *D, const CXXRecordDecl *B, - Index_t Offset = 0) { - - if (B == D) - return Offset; - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(D); - for (CXXRecordDecl::base_class_const_iterator i = D->bases_begin(), - e = D->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - int64_t BaseOffset = 0; - if (!i->isVirtual()) - BaseOffset = Offset + Layout.getBaseClassOffset(Base); - int64_t o = getNVOffset_1(Base, B, BaseOffset); - if (o >= 0) - return o; - } - - return -1; - } - - /// getNVOffset - Returns the non-virtual offset for the given (B) base of the - /// derived class D. - Index_t getNVOffset(QualType qB, QualType qD) { - qD = qD->getPointeeType(); - qB = qB->getPointeeType(); - CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); - CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); - int64_t o = getNVOffset_1(D, B); - if (o >= 0) - return o; - - assert(false && "FIXME: non-virtual base not found"); - return 0; - } - - /// getVbaseOffset - Returns the index into the vtable for the virtual base - /// offset for the given (B) virtual base of the derived class D. - Index_t getVbaseOffset(QualType qB, QualType qD) { - qD = qD->getPointeeType(); - qB = qB->getPointeeType(); - CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); - CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); - if (D != MostDerivedClass) - return CGM.getVtableInfo().getVirtualBaseOffsetOffset(D, B); - llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i; - i = VBIndex.find(B); - if (i != VBIndex.end()) - return i->second; - - assert(false && "FIXME: Base not found"); - return 0; - } - - bool OverrideMethod(GlobalDecl GD, bool MorallyVirtual, - Index_t OverrideOffset, Index_t Offset, - int64_t CurrentVBaseOffset); - - /// AppendMethods - Append the current methods to the vtable. - void AppendMethodsToVtable(); - - llvm::Constant *WrapAddrOf(GlobalDecl GD) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD); - - return wrap(CGM.GetAddrOfFunction(GD, Ty)); - } - - void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset, - int64_t CurrentVBaseOffset) { - for (Path_t::reverse_iterator i = Path->rbegin(), - e = Path->rend(); i != e; ++i) { - const CXXRecordDecl *RD = i->first; - int64_t OverrideOffset = i->second; - for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; - ++mi) { - const CXXMethodDecl *MD = *mi; - - if (!MD->isVirtual()) - continue; - - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - // Override both the complete and the deleting destructor. - GlobalDecl CompDtor(DD, Dtor_Complete); - OverrideMethod(CompDtor, MorallyVirtual, OverrideOffset, Offset, - CurrentVBaseOffset); - - GlobalDecl DeletingDtor(DD, Dtor_Deleting); - OverrideMethod(DeletingDtor, MorallyVirtual, OverrideOffset, Offset, - CurrentVBaseOffset); - } else { - OverrideMethod(MD, MorallyVirtual, OverrideOffset, Offset, - CurrentVBaseOffset); - } - } - } - } - - void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset, - int64_t CurrentVBaseOffset) { - // If we can find a previously allocated slot for this, reuse it. - if (OverrideMethod(GD, MorallyVirtual, Offset, Offset, - CurrentVBaseOffset)) - return; - - D1(printf(" vfn for %s at %d\n", - dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsString().c_str(), - (int)Methods.size())); - - // We didn't find an entry in the vtable that we could use, add a new - // entry. - Methods.AddMethod(GD); - - VCallOffset[GD] = Offset/8 - CurrentVBaseOffset/8; - - if (MorallyVirtual) { - GlobalDecl UGD = getUnique(GD); - const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl()); - - assert(UMD && "final overrider not found"); - - Index_t &idx = VCall[UMD]; - // Allocate the first one, after that, we reuse the previous one. - if (idx == 0) { - VCallOffsetForVCall[UGD] = Offset/8; - NonVirtualOffset[UMD] = Offset/8 - CurrentVBaseOffset/8; - idx = VCalls.size()+1; - VCalls.push_back(Offset/8 - CurrentVBaseOffset/8); - D1(printf(" vcall for %s at %d with delta %d\n", - dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsString().c_str(), - (int)-VCalls.size()-3, (int)VCalls[idx-1])); - } - } - } - - void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual, - Index_t Offset, int64_t CurrentVBaseOffset) { - for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; - ++mi) { - const CXXMethodDecl *MD = *mi; - if (!MD->isVirtual()) - continue; - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - // For destructors, add both the complete and the deleting destructor - // to the vtable. - AddMethod(GlobalDecl(DD, Dtor_Complete), MorallyVirtual, Offset, - CurrentVBaseOffset); - AddMethod(GlobalDecl(DD, Dtor_Deleting), MorallyVirtual, Offset, - CurrentVBaseOffset); - } else - AddMethod(MD, MorallyVirtual, Offset, CurrentVBaseOffset); - } - } + Out << '\n'; - void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, - const CXXRecordDecl *PrimaryBase, - bool PrimaryBaseWasVirtual, bool MorallyVirtual, - int64_t Offset, int64_t CurrentVBaseOffset, - Path_t *Path) { - Path->push_back(std::make_pair(RD, Offset)); - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - if (i->isVirtual()) - continue; - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - uint64_t o = Offset + Layout.getBaseClassOffset(Base); - StartNewTable(); - GenerateVtableForBase(Base, o, MorallyVirtual, false, - true, Base == PrimaryBase && !PrimaryBaseWasVirtual, - CurrentVBaseOffset, Path); } - Path->pop_back(); } - -// #define D(X) do { X; } while (0) -#define D(X) - - void insertVCalls(int InsertionPoint) { - D1(printf("============= combining vbase/vcall\n")); - D(VCalls.insert(VCalls.begin(), 673)); - D(VCalls.push_back(672)); - - VtableComponents.insert(VtableComponents.begin() + InsertionPoint, - VCalls.size(), 0); - if (BuildVtable) { - // The vcalls come first... - for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(), - e = VCalls.rend(); - i != e; ++i) - VtableComponents[InsertionPoint++] = wrap((0?600:0) + *i); - } - VCalls.clear(); - VCall.clear(); - VCallOffsetForVCall.clear(); - VCallOffset.clear(); - NonVirtualOffset.clear(); - } - - void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset, - Index_t AddressPoint) { - D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", - RD->getNameAsCString(), MostDerivedClass->getNameAsCString(), - LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); - subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; - AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint; - - // Now also add the address point for all our primary bases. - while (1) { - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - RD = Layout.getPrimaryBase(); - const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - // FIXME: Double check this. - if (RD == 0) - break; - if (PrimaryBaseWasVirtual && - BLayout.getVBaseClassOffset(RD) != Offset) - break; - D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", - RD->getNameAsCString(), MostDerivedClass->getNameAsCString(), - LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); - subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; - AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint; - } - } - - - void FinishGenerateVtable(const CXXRecordDecl *RD, - const ASTRecordLayout &Layout, - const CXXRecordDecl *PrimaryBase, - bool ForNPNVBases, bool WasPrimaryBase, - bool PrimaryBaseWasVirtual, - bool MorallyVirtual, int64_t Offset, - bool ForVirtualBase, int64_t CurrentVBaseOffset, - Path_t *Path) { - bool alloc = false; - if (Path == 0) { - alloc = true; - Path = new Path_t; - } - - StartNewTable(); - extra = 0; - Index_t AddressPoint = 0; - int VCallInsertionPoint = 0; - if (!ForNPNVBases || !WasPrimaryBase) { - bool DeferVCalls = MorallyVirtual || ForVirtualBase; - VCallInsertionPoint = VtableComponents.size(); - if (!DeferVCalls) { - insertVCalls(VCallInsertionPoint); - } else - // FIXME: just for extra, or for all uses of VCalls.size post this? - extra = -VCalls.size(); - - // Add the offset to top. - VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0); - - // Add the RTTI information. - VtableComponents.push_back(rtti); - - AddressPoint = VtableComponents.size(); - - AppendMethodsToVtable(); - } - - // and then the non-virtual bases. - NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, - MorallyVirtual, Offset, CurrentVBaseOffset, Path); - - if (ForVirtualBase) { - // FIXME: We're adding to VCalls in callers, we need to do the overrides - // in the inner part, so that we know the complete set of vcalls during - // the build and don't have to insert into methods. Saving out the - // AddressPoint here, would need to be fixed, if we didn't do that. Also - // retroactively adding vcalls for overrides later wind up in the wrong - // place, the vcall slot has to be alloted during the walk of the base - // when the function is first introduces. - AddressPoint += VCalls.size(); - insertVCalls(VCallInsertionPoint); - } - - if (!ForNPNVBases || !WasPrimaryBase) - AddAddressPoints(RD, Offset, AddressPoint); - - if (alloc) { - delete Path; - } - } - - void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, - bool updateVBIndex, Index_t current_vbindex, - int64_t CurrentVBaseOffset) { - if (!RD->isDynamicClass()) - return; - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - - // vtables are composed from the chain of primaries. - if (PrimaryBase && !PrimaryBaseWasVirtual) { - D1(printf(" doing primaries for %s most derived %s\n", - RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); - Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, - updateVBIndex, current_vbindex, CurrentVBaseOffset); - } - - D1(printf(" doing vcall entries for %s most derived %s\n", - RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); - - // And add the virtuals for the class to the primary vtable. - AddMethods(RD, MorallyVirtual, Offset, CurrentVBaseOffset); - } - - void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, - bool updateVBIndex, Index_t current_vbindex, - bool RDisVirtualBase, int64_t CurrentVBaseOffset, - bool bottom) { - if (!RD->isDynamicClass()) - return; - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - - // vtables are composed from the chain of primaries. - if (PrimaryBase) { - int BaseCurrentVBaseOffset = CurrentVBaseOffset; - if (PrimaryBaseWasVirtual) { - IndirectPrimary.insert(PrimaryBase); - BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase); - } - - D1(printf(" doing primaries for %s most derived %s\n", - RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); - - VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, - updateVBIndex, current_vbindex, PrimaryBaseWasVirtual, - BaseCurrentVBaseOffset, false); - } - - D1(printf(" doing vbase entries for %s most derived %s\n", - RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); - GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex); - - if (RDisVirtualBase || bottom) { - Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex, - CurrentVBaseOffset); - } - } - - void GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0, - bool MorallyVirtual = false, - bool ForVirtualBase = false, - bool ForNPNVBases = false, - bool WasPrimaryBase = true, - int CurrentVBaseOffset = 0, - Path_t *Path = 0) { - if (!RD->isDynamicClass()) - return; - - // Construction vtable don't need parts that have no virtual bases and - // aren't morally virtual. - if ((LayoutClass != MostDerivedClass) && - RD->getNumVBases() == 0 && !MorallyVirtual) - return; - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - - extra = 0; - D1(printf("building entries for base %s most derived %s\n", - RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); - - if (ForVirtualBase) - extra = VCalls.size(); - - if (!ForNPNVBases || !WasPrimaryBase) { - VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, - ForVirtualBase, CurrentVBaseOffset, true); - - if (Path) - OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); - } - - FinishGenerateVtable(RD, Layout, PrimaryBase, ForNPNVBases, WasPrimaryBase, - PrimaryBaseWasVirtual, MorallyVirtual, Offset, - ForVirtualBase, CurrentVBaseOffset, Path); - } - - void GenerateVtableForVBases(const CXXRecordDecl *RD, - int64_t Offset = 0, - Path_t *Path = 0) { - bool alloc = false; - if (Path == 0) { - alloc = true; - Path = new Path_t; - } - // FIXME: We also need to override using all paths to a virtual base, - // right now, we just process the first path - Path->push_back(std::make_pair(RD, Offset)); - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (i->isVirtual() && !IndirectPrimary.count(Base)) { - // Mark it so we don't output it twice. - IndirectPrimary.insert(Base); - StartNewTable(); - VCall.clear(); - int64_t BaseOffset = BLayout.getVBaseClassOffset(Base); - int64_t CurrentVBaseOffset = BaseOffset; - D1(printf("vtable %s virtual base %s\n", - MostDerivedClass->getNameAsCString(), Base->getNameAsCString())); - GenerateVtableForBase(Base, BaseOffset, true, true, false, - true, CurrentVBaseOffset, Path); - } - int64_t BaseOffset; - if (i->isVirtual()) - BaseOffset = BLayout.getVBaseClassOffset(Base); - else { - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - BaseOffset = Offset + Layout.getBaseClassOffset(Base); - } - - if (Base->getNumVBases()) { - GenerateVtableForVBases(Base, BaseOffset, Path); - } - } - Path->pop_back(); - if (alloc) - delete Path; - } -}; -} // end anonymous namespace - -bool OldVtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, - Index_t OverrideOffset, Index_t Offset, - int64_t CurrentVBaseOffset) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - const bool isPure = MD->isPure(); - - // FIXME: Should OverrideOffset's be Offset? - - for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(), - e = MD->end_overridden_methods(); mi != e; ++mi) { - GlobalDecl OGD; - GlobalDecl OGD2; - - const CXXMethodDecl *OMD = *mi; - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD)) - OGD = GlobalDecl(DD, GD.getDtorType()); - else - OGD = OMD; - - // Check whether this is the method being overridden in this section of - // the vtable. - uint64_t Index; - if (!Methods.getIndex(OGD, Index)) - continue; - - OGD2 = OGD; - - // Get the original method, which we should be computing thunks, etc, - // against. - OGD = Methods.getOrigMethod(Index); - OMD = cast<CXXMethodDecl>(OGD.getDecl()); - - QualType ReturnType = - MD->getType()->getAs<FunctionType>()->getResultType(); - QualType OverriddenReturnType = - OMD->getType()->getAs<FunctionType>()->getResultType(); - - // Check if we need a return type adjustment. - if (!ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, - OMD).isEmpty()) { - CanQualType &BaseReturnType = BaseReturnTypes[Index]; - - // Insert the base return type. - if (BaseReturnType.isNull()) - BaseReturnType = - CGM.getContext().getCanonicalType(OverriddenReturnType); - } - - Methods.OverrideMethod(OGD, GD); - - GlobalDecl UGD = getUnique(GD); - const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl()); - assert(UGD.getDecl() && "unique overrider not found"); - assert(UGD == getUnique(OGD) && "unique overrider not unique"); - - ThisAdjustments.erase(Index); - if (MorallyVirtual || VCall.count(UMD)) { - - Index_t &idx = VCall[UMD]; - if (idx == 0) { - VCallOffset[GD] = VCallOffset[OGD]; - // NonVirtualOffset[UMD] = CurrentVBaseOffset/8 - OverrideOffset/8; - NonVirtualOffset[UMD] = VCallOffset[OGD]; - VCallOffsetForVCall[UMD] = OverrideOffset/8; - idx = VCalls.size()+1; - VCalls.push_back(OverrideOffset/8 - CurrentVBaseOffset/8); - D1(printf(" vcall for %s at %d with delta %d most derived %s\n", - MD->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], MostDerivedClass->getNameAsCString())); - } else { - VCallOffset[GD] = NonVirtualOffset[UMD]; - VCalls[idx-1] = -VCallOffsetForVCall[UGD] + OverrideOffset/8; - D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n", - MD->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], MostDerivedClass->getNameAsCString())); - } - int64_t NonVirtualAdjustment = -VCallOffset[OGD]; - QualType DerivedType = MD->getThisType(CGM.getContext()); - QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext()); - int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8); - if (NonVirtualAdjustment2 != NonVirtualAdjustment) { - NonVirtualAdjustment = NonVirtualAdjustment2; - } - int64_t VirtualAdjustment = - -((idx + extra + 2) * LLVMPointerWidth / 8); - - // Optimize out virtual adjustments of 0. - if (VCalls[idx-1] == 0) - VirtualAdjustment = 0; - - ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, - VirtualAdjustment); - - if (!isPure && !ThisAdjustment.isEmpty()) { - ThisAdjustments[Index] = ThisAdjustment; - SavedAdjustments.push_back( - std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); - } - return true; - } - - VCallOffset[GD] = VCallOffset[OGD2] - OverrideOffset/8; - - int64_t NonVirtualAdjustment = -VCallOffset[GD]; - QualType DerivedType = MD->getThisType(CGM.getContext()); - QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext()); - int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8); - if (NonVirtualAdjustment2 != NonVirtualAdjustment) { - NonVirtualAdjustment = NonVirtualAdjustment2; - } - - if (NonVirtualAdjustment) { - ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0); - - if (!isPure) { - ThisAdjustments[Index] = ThisAdjustment; - SavedAdjustments.push_back( - std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); - } - } - return true; - } - - return false; } - -void OldVtableBuilder::AppendMethodsToVtable() { - if (!BuildVtable) { - VtableComponents.insert(VtableComponents.end(), Methods.size(), - (llvm::Constant *)0); - ThisAdjustments.clear(); - BaseReturnTypes.clear(); - Methods.clear(); - return; - } - - // Reserve room in the vtable for our new methods. - VtableComponents.reserve(VtableComponents.size() + Methods.size()); - - for (unsigned i = 0, e = Methods.size(); i != e; ++i) { - GlobalDecl GD = Methods[i]; - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - // Get the 'this' pointer adjustment. - ThunkAdjustment ThisAdjustment = ThisAdjustments.lookup(i); - - // Construct the return type adjustment. - ThunkAdjustment ReturnAdjustment; - - QualType BaseReturnType = BaseReturnTypes.lookup(i); - if (!BaseReturnType.isNull() && !MD->isPure()) { - QualType DerivedType = - MD->getType()->getAs<FunctionType>()->getResultType(); - - int64_t NonVirtualAdjustment = - getNVOffset(BaseReturnType, DerivedType) / 8; - - int64_t VirtualAdjustment = - getVbaseOffset(BaseReturnType, DerivedType); - - ReturnAdjustment = ThunkAdjustment(NonVirtualAdjustment, - VirtualAdjustment); - } - - llvm::Constant *Method = 0; - if (!ReturnAdjustment.isEmpty()) { - // Build a covariant thunk. - CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment); - Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment)); - } else if (!ThisAdjustment.isEmpty()) { - // Build a "regular" thunk. - Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment)); - } else if (MD->isPure()) { - // We have a pure virtual method. - Method = getPureVirtualFn(); - } else { - // We have a good old regular method. - Method = WrapAddrOf(GD); - } - - // Add the method to the vtable. - VtableComponents.push_back(Method); - } - - ThisAdjustments.clear(); - BaseReturnTypes.clear(); - - Methods.clear(); } -void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { +void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Itanium C++ ABI 2.5.2: // The order of the virtual function pointers in a virtual table is the @@ -3481,7 +2479,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { NumVirtualFunctionPointers[RD] = CurrentIndex; } -uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { +uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = NumVirtualFunctionPointers.find(RD); if (I != NumVirtualFunctionPointers.end()) @@ -3494,7 +2492,7 @@ uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { return I->second; } -uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { +uint64_t CodeGenVTables::getMethodVtableIndex(GlobalDecl GD) { MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD); if (I != MethodVtableIndices.end()) return I->second; @@ -3508,36 +2506,8 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { return I->second; } -CGVtableInfo::AdjustmentVectorTy* -CGVtableInfo::getAdjustments(GlobalDecl GD) { - SavedAdjustmentsTy::iterator I = SavedAdjustments.find(GD); - if (I != SavedAdjustments.end()) - return &I->second; - - const CXXRecordDecl *RD = cast<CXXRecordDecl>(GD.getDecl()->getDeclContext()); - if (!SavedAdjustmentRecords.insert(RD).second) - return 0; - - AddressPointsMapTy AddressPoints; - OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints); - D1(printf("vtable %s\n", RD->getNameAsCString())); - b.GenerateVtableForBase(RD); - b.GenerateVtableForVBases(RD); - - for (OldVtableBuilder::SavedAdjustmentsVectorTy::iterator - i = b.getSavedAdjustments().begin(), - e = b.getSavedAdjustments().end(); i != e; i++) - SavedAdjustments[i->first].push_back(i->second); - - I = SavedAdjustments.find(GD); - if (I != SavedAdjustments.end()) - return &I->second; - - return 0; -} - -int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase) { +int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase) { ClassPairTy ClassPair(RD, VBase); VirtualBaseClassOffsetOffsetsMapTy::iterator I = @@ -3549,7 +2519,6 @@ int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, BaseSubobject(RD, 0), /*BaseIsVirtual=*/false, /*OffsetInLayoutClass=*/0); - for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = Builder.getVBaseOffsetOffsets().begin(), @@ -3573,128 +2542,588 @@ int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, return I->second; } -uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) { - uint64_t AddressPoint = - (*(*(CGM.getVtableInfo().AddressPoints[RD]))[RD])[std::make_pair(RD, 0)]; - +uint64_t +CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) { + uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base)); + assert(AddressPoint && "Address point must not be zero!"); + return AddressPoint; } -llvm::GlobalVariable * -CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, - bool GenerateDefinition, - const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, uint64_t Offset, - bool IsVirtual, - AddressPointsMapTy& AddressPoints) { - if (GenerateDefinition) { - if (LayoutClass == RD) { - assert(!IsVirtual && - "Can only have a virtual base in construction vtables!"); - assert(!Offset && - "Can only have a base offset in construction vtables!"); - } +llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, + const ThunkInfo &Thunk) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Compute the mangled name. + llvm::SmallString<256> Name; + if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD)) + getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), Thunk.This, + Name); + else + getMangleContext().mangleThunk(MD, Thunk, Name); + + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, + llvm::Value *Ptr, + int64_t NonVirtualAdjustment, + int64_t VirtualAdjustment) { + if (!NonVirtualAdjustment && !VirtualAdjustment) + return Ptr; + + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + + llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); + + if (NonVirtualAdjustment) { + // Do the non-virtual adjustment. + V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment); + } + + if (VirtualAdjustment) { + const llvm::Type *PtrDiffTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); + + // Do the virtual adjustment. + llvm::Value *VTablePtrPtr = + CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo()); + + llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr); + + llvm::Value *OffsetPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment); + + OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo()); + + // Load the adjustment offset from the vtable. + llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr); - VtableBuilder Builder(*this, RD, Offset, - /*MostDerivedClassIsVirtual=*/IsVirtual, - LayoutClass); + // Adjust our pointer. + V = CGF.Builder.CreateInBoundsGEP(V, Offset); + } + + // Cast back to the original type. + return CGF.Builder.CreateBitCast(V, Ptr->getType()); +} + +void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, + const ThunkInfo &Thunk) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + QualType ResultType = FPT->getResultType(); + QualType ThisType = MD->getThisType(getContext()); - if (CGM.getLangOptions().DumpVtableLayouts) - Builder.dumpLayout(llvm::errs()); + FunctionArgList FunctionArgs; + + // FIXME: It would be nice if more of this code could be shared with + // CodeGenFunction::GenerateCode. + + // Create the implicit 'this' parameter declaration. + CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, + MD->getLocation(), + &getContext().Idents.get("this"), + ThisType); + + // Add the 'this' parameter. + FunctionArgs.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); + + // 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; + + FunctionArgs.push_back(std::make_pair(Param, Param->getType())); } + + StartFunction(GlobalDecl(), ResultType, Fn, FunctionArgs, SourceLocation()); - llvm::SmallString<256> OutName; - if (LayoutClass != RD) - CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8, - RD, OutName); - else - CGM.getMangleContext().mangleCXXVtable(RD, OutName); - llvm::StringRef Name = OutName.str(); + // Adjust the 'this' pointer if necessary. + llvm::Value *AdjustedThisPtr = + PerformTypeAdjustment(*this, LoadCXXThis(), + Thunk.This.NonVirtual, + Thunk.This.VCallOffsetOffset); + + CallArgList CallArgs; + + // Add our adjusted 'this' pointer. + CallArgs.push_back(std::make_pair(RValue::get(AdjustedThisPtr), ThisType)); - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); - if (GV == 0 || CGM.getVtableInfo().AddressPoints[LayoutClass] == 0 || - GV->isDeclaration()) { - OldVtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition, - AddressPoints); + // 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(); + + // FIXME: Declaring a DeclRefExpr on the stack is kinda icky. + DeclRefExpr ArgExpr(Param, ArgType.getNonReferenceType(), SourceLocation()); + CallArgs.push_back(std::make_pair(EmitCallArg(&ArgExpr, ArgType), ArgType)); + } - D1(printf("vtable %s\n", RD->getNameAsCString())); - // First comes the vtables for all the non-virtual bases... - b.GenerateVtableForBase(RD, Offset); + // Get our callee. + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); - // then the vtables for all the virtual bases. - b.GenerateVtableForVBases(RD, Offset); + const CGFunctionInfo &FnInfo = + CGM.getTypes().getFunctionInfo(ResultType, CallArgs, + FPT->getExtInfo()); + + // Now emit our call. + RValue RV = EmitCall(FnInfo, Callee, ReturnValueSlot(), CallArgs, MD); + + if (!Thunk.Return.isEmpty()) { + // Emit the return adjustment. + bool NullCheckValue = !ResultType->isReferenceType(); + + llvm::BasicBlock *AdjustNull = 0; + llvm::BasicBlock *AdjustNotNull = 0; + llvm::BasicBlock *AdjustEnd = 0; + + llvm::Value *ReturnValue = RV.getScalarVal(); - llvm::Constant *Init = 0; - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - llvm::ArrayType *ArrayType = - llvm::ArrayType::get(Int8PtrTy, b.getVtableComponents().size()); - - if (GenerateDefinition) - Init = llvm::ConstantArray::get(ArrayType, &b.getVtableComponents()[0], - b.getVtableComponents().size()); - - llvm::GlobalVariable *OGV = GV; - - GV = new llvm::GlobalVariable(CGM.getModule(), ArrayType, - /*isConstant=*/true, Linkage, Init, Name); - CGM.setGlobalVisibility(GV, RD); - - if (OGV) { - GV->takeName(OGV); - llvm::Constant *NewPtr = - llvm::ConstantExpr::getBitCast(GV, OGV->getType()); - OGV->replaceAllUsesWith(NewPtr); - OGV->eraseFromParent(); + if (NullCheckValue) { + AdjustNull = createBasicBlock("adjust.null"); + AdjustNotNull = createBasicBlock("adjust.notnull"); + AdjustEnd = createBasicBlock("adjust.end"); + + llvm::Value *IsNull = Builder.CreateIsNull(ReturnValue); + Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull); + EmitBlock(AdjustNotNull); + } + + ReturnValue = PerformTypeAdjustment(*this, ReturnValue, + Thunk.Return.NonVirtual, + Thunk.Return.VBaseOffsetOffset); + + if (NullCheckValue) { + Builder.CreateBr(AdjustEnd); + EmitBlock(AdjustNull); + Builder.CreateBr(AdjustEnd); + EmitBlock(AdjustEnd); + + llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType()); + PHI->reserveOperandSpace(2); + PHI->addIncoming(ReturnValue, AdjustNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()), + AdjustNull); + ReturnValue = PHI; } + + RV = RValue::get(ReturnValue); } + + if (!ResultType->isVoidType()) + EmitReturnOfRValue(RV, ResultType); + + FinishFunction(); + + // Destroy the 'this' declaration. + CXXThisDecl->Destroy(getContext()); - return GV; + // Set the right linkage. + Fn->setLinkage(CGM.getFunctionLinkage(MD)); + + // Set the right visibility. + CGM.setGlobalVisibility(Fn, MD); } -void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD) { - llvm::GlobalVariable *&Vtable = Vtables[RD]; - if (Vtable) { - assert(Vtable->getInitializer() && "Vtable doesn't have a definition!"); +void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) +{ + llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk); + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Strip off a bitcast if we got one back. + if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Entry)) { + assert(CE->getOpcode() == llvm::Instruction::BitCast); + Entry = CE->getOperand(0); + } + + // There's already a declaration with the same name, check if it has the same + // type or if we need to replace it. + if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() != + CGM.getTypes().GetFunctionTypeForVtable(MD)) { + llvm::GlobalValue *OldThunkFn = cast<llvm::GlobalValue>(Entry); + + // If the types mismatch then we have to rewrite the definition. + assert(OldThunkFn->isDeclaration() && + "Shouldn't replace non-declaration"); + + // Remove the name from the old thunk function and get a new thunk. + OldThunkFn->setName(llvm::StringRef()); + Entry = CGM.GetAddrOfThunk(GD, Thunk); + + // If needed, replace the old thunk with a bitcast. + if (!OldThunkFn->use_empty()) { + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(Entry, OldThunkFn->getType()); + OldThunkFn->replaceAllUsesWith(NewPtrForOldDecl); + } + + // Remove the old thunk. + OldThunkFn->eraseFromParent(); + } + + // Actually generate the thunk body. + llvm::Function *ThunkFn = cast<llvm::Function>(Entry); + CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk); +} + +void CodeGenVTables::EmitThunks(GlobalDecl GD) +{ + const CXXMethodDecl *MD = + cast<CXXMethodDecl>(GD.getDecl())->getCanonicalDecl(); + + // We don't need to generate thunks for the base destructor. + if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) + return; + + const CXXRecordDecl *RD = MD->getParent(); + + // Compute VTable related info for this class. + ComputeVTableRelatedInformation(RD); + + ThunksMapTy::const_iterator I = Thunks.find(MD); + if (I == Thunks.end()) { + // We did not find a thunk for this method. return; } + + const ThunkInfoVectorTy &ThunkInfoVector = I->second; + for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I) + EmitThunk(GD, ThunkInfoVector[I]); +} + +void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { + uint64_t *&LayoutData = VTableLayoutMap[RD]; - AddressPointsMapTy AddressPoints; - Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0, - /*IsVirtual=*/false, - AddressPoints); - GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); + // Check if we've computed this information before. + if (LayoutData) + return; + + VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); - for (CXXRecordDecl::method_iterator i = RD->method_begin(), - e = RD->method_end(); i != e; ++i) { - if (!(*i)->isVirtual()) - continue; - if(!(*i)->hasInlineBody() && !(*i)->isImplicit()) - continue; + // Add the VTable layout. + uint64_t NumVTableComponents = Builder.getNumVTableComponents(); + LayoutData = new uint64_t[NumVTableComponents + 1]; - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(*i)) { - CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete)); - CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting)); - } else { - CGM.BuildThunksForVirtual(GlobalDecl(*i)); + // Store the number of components. + LayoutData[0] = NumVTableComponents; + + // Store the components. + std::copy(Builder.vtable_components_data_begin(), + Builder.vtable_components_data_end(), + &LayoutData[1]); + + // Add the known thunks. + Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); + + // Add the thunks needed in this vtable. + assert(!VTableThunksMap.count(RD) && + "Thunks already exists for this vtable!"); + + VTableThunksTy &VTableThunks = VTableThunksMap[RD]; + VTableThunks.append(Builder.vtable_thunks_begin(), + Builder.vtable_thunks_end()); + + // Sort them. + std::sort(VTableThunks.begin(), VTableThunks.end()); + + // Add the address points. + for (VtableBuilder::AddressPointsMapTy::const_iterator I = + Builder.address_points_begin(), E = Builder.address_points_end(); + I != E; ++I) { + + uint64_t &AddressPoint = AddressPoints[std::make_pair(RD, I->first)]; + + // Check if we already have the address points for this base. + assert(!AddressPoint && "Address point already exists for this base!"); + + AddressPoint = I->second; + } + + // If we don't have the vbase information for this class, insert it. + // getVirtualBaseOffsetOffset will compute it separately without computing + // the rest of the vtable related information. + if (!RD->getNumVBases()) + return; + + const RecordType *VBaseRT = + RD->vbases_begin()->getType()->getAs<RecordType>(); + const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl()); + + if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase))) + return; + + for (VtableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = + Builder.getVBaseOffsetOffsets().begin(), + E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { + // Insert all types. + ClassPairTy ClassPair(RD, I->first); + + VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second)); + } +} + +llvm::Constant * +CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, + const uint64_t *Components, + unsigned NumComponents, + const VTableThunksTy &VTableThunks) { + llvm::SmallVector<llvm::Constant *, 64> Inits; + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + + const llvm::Type *PtrDiffTy = + CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); + + QualType ClassType = CGM.getContext().getTagDeclType(RD); + llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType); + + unsigned NextVTableThunkIndex = 0; + + llvm::Constant* PureVirtualFn = 0; + + for (unsigned I = 0; I != NumComponents; ++I) { + VtableComponent Component = + VtableComponent::getFromOpaqueInteger(Components[I]); + + llvm::Constant *Init = 0; + + switch (Component.getKind()) { + case VtableComponent::CK_VCallOffset: + Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset()); + Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); + break; + case VtableComponent::CK_VBaseOffset: + Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset()); + Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); + break; + case VtableComponent::CK_OffsetToTop: + Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop()); + Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); + break; + case VtableComponent::CK_RTTI: + Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy); + break; + case VtableComponent::CK_FunctionPointer: + case VtableComponent::CK_CompleteDtorPointer: + case VtableComponent::CK_DeletingDtorPointer: { + GlobalDecl GD; + + // Get the right global decl. + switch (Component.getKind()) { + default: + llvm_unreachable("Unexpected vtable component kind"); + case VtableComponent::CK_FunctionPointer: + GD = Component.getFunctionDecl(); + break; + case VtableComponent::CK_CompleteDtorPointer: + GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete); + break; + case VtableComponent::CK_DeletingDtorPointer: + GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting); + break; + } + + if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) { + // We have a pure virtual member function. + if (!PureVirtualFn) { + const llvm::FunctionType *Ty = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), + /*isVarArg=*/false); + PureVirtualFn = + CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual"); + PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn, + Int8PtrTy); + } + + Init = PureVirtualFn; + } else { + // Check if we should use a thunk. + if (NextVTableThunkIndex < VTableThunks.size() && + VTableThunks[NextVTableThunkIndex].first == I) { + const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second; + + Init = CGM.GetAddrOfThunk(GD, Thunk); + + NextVTableThunkIndex++; + } else { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD); + + Init = CGM.GetAddrOfFunction(GD, Ty); + } + + Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); + } + break; + } + + case VtableComponent::CK_UnusedFunctionPointer: + Init = llvm::ConstantExpr::getNullValue(Int8PtrTy); + break; + }; + + Inits.push_back(Init); + } + + llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents); + return llvm::ConstantArray::get(ArrayType, Inits.data(), Inits.size()); +} + +/// GetGlobalVariable - Will return a global variable of the given type. +/// If a variable with a different type already exists then a new variable +/// with the right type will be created. +/// FIXME: We should move this to CodeGenModule and rename it to something +/// better and then use it in CGVTT and CGRTTI. +static llvm::GlobalVariable * +GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name, + const llvm::Type *Ty, + llvm::GlobalValue::LinkageTypes Linkage) { + + llvm::GlobalVariable *GV = Module.getNamedGlobal(Name); + llvm::GlobalVariable *OldGV = 0; + + if (GV) { + // Check if the variable has the right type. + if (GV->getType()->getElementType() == Ty) + return GV; + + assert(GV->isDeclaration() && "Declaration has wrong type!"); + + OldGV = GV; + } + + // Create a new variable. + GV = new llvm::GlobalVariable(Module, Ty, /*isConstant=*/true, + Linkage, 0, Name); + + if (OldGV) { + // Replace occurrences of the old variable if needed. + GV->takeName(OldGV); + + if (!OldGV->use_empty()) { + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtrForOldDecl); } + + OldGV->eraseFromParent(); } + + return GV; } -llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { - llvm::GlobalVariable *Vtable = Vtables.lookup(RD); +llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXVtable(RD, OutName); + llvm::StringRef Name = OutName.str(); + + ComputeVTableRelatedInformation(RD); - if (!Vtable) { - AddressPointsMapTy AddressPoints; - Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage, - /*GenerateDefinition=*/false, RD, RD, 0, - /*IsVirtual=*/false, AddressPoints); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, getNumVTableComponents(RD)); + + return GetGlobalVariable(CGM.getModule(), Name, ArrayType, + llvm::GlobalValue::ExternalLinkage); +} + +void +CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable, + llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { + // Dump the vtable layout if necessary. + if (CGM.getLangOptions().DumpVtableLayouts) { + VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); + + Builder.dumpLayout(llvm::errs()); } - return Vtable; + assert(VTableThunksMap.count(RD) && + "No thunk status for this record decl!"); + + const VTableThunksTy& Thunks = VTableThunksMap[RD]; + + // Create and set the initializer. + llvm::Constant *Init = + CreateVTableInitializer(RD, getVTableComponentsData(RD), + getNumVTableComponents(RD), Thunks); + VTable->setInitializer(Init); + + // Set the correct linkage. + VTable->setLinkage(Linkage); } -void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { +llvm::GlobalVariable * +CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, + const BaseSubobject &Base, + bool BaseIsVirtual, + VTableAddressPointsMapTy& AddressPoints) { + VtableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(), + /*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD); + + // Dump the vtable layout if necessary. + if (CGM.getLangOptions().DumpVtableLayouts) + Builder.dumpLayout(llvm::errs()); + + // Add the address points. + AddressPoints.insert(Builder.address_points_begin(), + Builder.address_points_end()); + + // Get the mangled construction vtable name. + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXCtorVtable(RD, Base.getBaseOffset() / 8, + Base.getBase(), OutName); + llvm::StringRef Name = OutName.str(); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, Builder.getNumVTableComponents()); + + // Create the variable that will hold the construction vtable. + llvm::GlobalVariable *VTable = + GetGlobalVariable(CGM.getModule(), Name, ArrayType, + llvm::GlobalValue::InternalLinkage); + + // Add the thunks. + VTableThunksTy VTableThunks; + VTableThunks.append(Builder.vtable_thunks_begin(), + Builder.vtable_thunks_end()); + + // Sort them. + std::sort(VTableThunks.begin(), VTableThunks.end()); + + // Create and set the initializer. + llvm::Constant *Init = + CreateVTableInitializer(Base.getBase(), + Builder.vtable_components_data_begin(), + Builder.getNumVTableComponents(), VTableThunks); + VTable->setInitializer(Init); + + return VTable; +} + +void +CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { + llvm::GlobalVariable *&VTable = Vtables[RD]; + if (VTable) { + assert(VTable->getInitializer() && "Vtable doesn't have a definition!"); + return; + } + + VTable = GetAddrOfVTable(RD); + EmitVTableDefinition(VTable, Linkage, RD); + + GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); +} + +void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const CXXRecordDecl *RD = MD->getParent(); @@ -3702,20 +3131,34 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { if (!RD->isDynamicClass()) return; + // Check if we need to emit thunks for this function. + if (MD->isVirtual()) + EmitThunks(GD); + // Get the key function. const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD); + TemplateSpecializationKind RDKind = RD->getTemplateSpecializationKind(); + TemplateSpecializationKind MDKind = MD->getTemplateSpecializationKind(); + if (KeyFunction) { // We don't have the right key function. if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) return; + } else { + // If this is an explicit instantiation of a method, we don't need a vtable. + // Since we have no key function, we will emit the vtable when we see + // a use, and just defining a function is not an use. + if ((RDKind == TSK_ImplicitInstantiation || + RDKind == TSK_ExplicitInstantiationDeclaration) && + MDKind == TSK_ExplicitInstantiationDefinition) + return; } if (Vtables.count(RD)) return; - TemplateSpecializationKind kind = RD->getTemplateSpecializationKind(); - if (kind == TSK_ImplicitInstantiation) + if (RDKind == TSK_ImplicitInstantiation) CGM.DeferredVtables.push_back(RD); else GenerateClassData(CGM.getVtableLinkage(RD), RD); diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index 5a146ab..6073555 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -15,7 +15,6 @@ #define CLANG_CODEGEN_CGVTABLE_H #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/GlobalVariable.h" #include "GlobalDecl.h" @@ -25,41 +24,93 @@ namespace clang { namespace CodeGen { class CodeGenModule; -/// ThunkAdjustment - Virtual and non-virtual adjustment for thunks. -class ThunkAdjustment { -public: - ThunkAdjustment(int64_t NonVirtual, int64_t Virtual) - : NonVirtual(NonVirtual), - Virtual(Virtual) { } - - ThunkAdjustment() - : NonVirtual(0), Virtual(0) { } +/// ReturnAdjustment - A return adjustment. +struct ReturnAdjustment { + /// NonVirtual - The non-virtual adjustment from the derived object to its + /// nearest virtual base. + int64_t NonVirtual; + + /// VBaseOffsetOffset - The offset (in bytes), relative to the address point + /// of the virtual base class offset. + int64_t VBaseOffsetOffset; + + ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { } + + bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } - // isEmpty - Return whether this thunk adjustment is empty. - bool isEmpty() const { - return NonVirtual == 0 && Virtual == 0; + friend bool operator==(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset; } - /// NonVirtual - The non-virtual adjustment. + friend bool operator<(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset; + } +}; + +/// ThisAdjustment - A 'this' pointer adjustment. +struct ThisAdjustment { + /// NonVirtual - The non-virtual adjustment from the derived object to its + /// nearest virtual base. int64_t NonVirtual; - /// Virtual - The virtual adjustment. - int64_t Virtual; + /// VCallOffsetOffset - The offset (in bytes), relative to the address point, + /// of the virtual call offset. + int64_t VCallOffsetOffset; + + ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { } + + bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } + + friend bool operator==(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VCallOffsetOffset == RHS.VCallOffsetOffset; + } + + friend bool operator<(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VCallOffsetOffset < RHS.VCallOffsetOffset; + } }; -/// CovariantThunkAdjustment - Adjustment of the 'this' pointer and the -/// return pointer for covariant thunks. -class CovariantThunkAdjustment { -public: - CovariantThunkAdjustment(const ThunkAdjustment &ThisAdjustment, - const ThunkAdjustment &ReturnAdjustment) - : ThisAdjustment(ThisAdjustment), ReturnAdjustment(ReturnAdjustment) { } +/// ThunkInfo - The 'this' pointer adjustment as well as an optional return +/// adjustment for a thunk. +struct ThunkInfo { + /// This - The 'this' pointer adjustment. + ThisAdjustment This; + + /// Return - The return adjustment. + ReturnAdjustment Return; - CovariantThunkAdjustment() { } + ThunkInfo() { } - ThunkAdjustment ThisAdjustment; - ThunkAdjustment ReturnAdjustment; -}; + ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return) + : This(This), Return(Return) { } + + friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { + return LHS.This == RHS.This && LHS.Return == RHS.Return; + } + + friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) { + if (LHS.This < RHS.This) + return true; + + return LHS.This == RHS.This && LHS.Return < RHS.Return; + } + + bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); } +}; // BaseSubobject - Uniquely identifies a direct or indirect base class. // Stores both the base class decl and the offset from the most derived class to @@ -126,19 +177,7 @@ template <> struct isPodLike<clang::CodeGen::BaseSubobject> { namespace clang { namespace CodeGen { -class CGVtableInfo { -public: - typedef std::vector<std::pair<GlobalDecl, ThunkAdjustment> > - AdjustmentVectorTy; - - typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; - typedef llvm::DenseMap<CtorVtable_t, int64_t> AddrSubMap_t; - typedef llvm::DenseMap<const CXXRecordDecl *, AddrSubMap_t *> AddrMap_t; - llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints; - - typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; - -private: +class CodeGenVTables { CodeGenModule &CGM; /// MethodVtableIndices - Contains the index (relative to the vtable address @@ -163,31 +202,97 @@ private: /// pointers in the vtable for a given record decl. llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers; - typedef llvm::DenseMap<GlobalDecl, AdjustmentVectorTy> SavedAdjustmentsTy; - SavedAdjustmentsTy SavedAdjustments; - llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords; + typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; + typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; + + /// Thunks - Contains all thunks that a given method decl will need. + ThunksMapTy Thunks; + + typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t *> VTableLayoutMapTy; + + /// VTableLayoutMap - Stores the vtable layout for all record decls. + /// The layout is stored as an array of 64-bit integers, where the first + /// integer is the number of vtable entries in the layout, and the subsequent + /// integers are the vtable components. + VTableLayoutMapTy VTableLayoutMap; + + typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, + BaseSubobject>, uint64_t> AddressPointsMapTy; + + /// Address points - Address points for all vtables. + AddressPointsMapTy AddressPoints; + + /// VTableAddressPointsMapTy - Address points for a single vtable. + typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy; + + typedef llvm::SmallVector<std::pair<uint64_t, ThunkInfo>, 1> + VTableThunksTy; + + typedef llvm::DenseMap<const CXXRecordDecl *, VTableThunksTy> + VTableThunksMapTy; + + /// VTableThunksMap - Contains thunks needed by vtables. + VTableThunksMapTy VTableThunksMap; + + uint64_t getNumVTableComponents(const CXXRecordDecl *RD) const { + assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); + + return VTableLayoutMap.lookup(RD)[0]; + } + + const uint64_t *getVTableComponentsData(const CXXRecordDecl *RD) const { + assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); + + uint64_t *Components = VTableLayoutMap.lookup(RD); + return &Components[1]; + } + + typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesMapTy; + + /// SubVTTIndicies - Contains indices into the various sub-VTTs. + SubVTTIndiciesMapTy SubVTTIndicies; + + + typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, + BaseSubobject>, uint64_t> + SecondaryVirtualPointerIndicesMapTy; - typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesTy; - SubVTTIndiciesTy SubVTTIndicies; + /// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer + /// indices. + SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; /// getNumVirtualFunctionPointers - Return the number of virtual function /// pointers in the vtable for a given record decl. uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); void ComputeMethodVtableIndices(const CXXRecordDecl *RD); - - llvm::GlobalVariable * - GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, - bool GenerateDefinition, const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, uint64_t Offset, bool IsVirtual, - AddressPointsMapTy& AddressPoints); llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, bool GenerateDefinition, const CXXRecordDecl *RD); + /// EmitThunk - Emit a single thunk. + void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk); + + /// EmitThunks - Emit the associated thunks for the given global decl. + void EmitThunks(GlobalDecl GD); + + /// ComputeVTableRelatedInformation - Compute and store all vtable related + /// information (vtable layout, vbase offset offsets, thunks etc) for the + /// given record decl. + void ComputeVTableRelatedInformation(const CXXRecordDecl *RD); + + /// CreateVTableInitializer - Create a vtable initializer for the given record + /// decl. + /// \param Components - The vtable components; this is really an array of + /// VTableComponents. + llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD, + const uint64_t *Components, + unsigned NumComponents, + const VTableThunksTy &VTableThunks); + public: - CGVtableInfo(CodeGenModule &CGM) + CodeGenVTables(CodeGenModule &CGM) : CGM(CGM) { } /// needsVTTParameter - Return whether the given global decl needs a VTT @@ -199,6 +304,11 @@ public: /// given record decl. uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base); + /// getSecondaryVirtualPointerIndex - Return the index in the VTT where the + /// virtual pointer for the given subobject is located. + uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, + BaseSubobject Base); + /// getMethodVtableIndex - Return the index (relative to the vtable address /// point) where the function pointer for the given virtual function is /// stored. @@ -212,35 +322,32 @@ public: int64_t getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, const CXXRecordDecl *VBase); - AdjustmentVectorTy *getAdjustments(GlobalDecl GD); - - /// getVtableAddressPoint - returns the address point of the vtable for the - /// given record decl. - /// FIXME: This should return a list of address points. - uint64_t getVtableAddressPoint(const CXXRecordDecl *RD); - - llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD); - - /// CtorVtableInfo - Information about a constructor vtable. - struct CtorVtableInfo { - /// Vtable - The vtable itself. - llvm::GlobalVariable *Vtable; + /// getAddressPoint - Get the address point of the given subobject in the + /// class decl. + uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD); - /// AddressPoints - The address points in this constructor vtable. - AddressPointsMapTy AddressPoints; - - CtorVtableInfo() : Vtable(0) { } - }; + /// GetAddrOfVTable - Get the address of the vtable for the given record decl. + llvm::GlobalVariable *GetAddrOfVTable(const CXXRecordDecl *RD); + + /// EmitVTableDefinition - Emit the definition of the given vtable. + void EmitVTableDefinition(llvm::GlobalVariable *VTable, + llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); - CtorVtableInfo getCtorVtable(const CXXRecordDecl *RD, - const BaseSubobject &Base, - bool BaseIsVirtual); + /// GenerateConstructionVTable - Generate a construction vtable for the given + /// base subobject. + llvm::GlobalVariable * + GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base, + bool BaseIsVirtual, + VTableAddressPointsMapTy& AddressPoints); llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD); - void MaybeEmitVtable(GlobalDecl GD); + // EmitVTableRelatedData - Will emit any thunks that the global decl might + // have, as well as the vtable itself if the global decl is the key function. + void EmitVTableRelatedData(GlobalDecl GD); - /// GenerateClassData - Generate all the class data requires to be generated + /// GenerateClassData - Generate all the class data required to be generated /// upon definition of a KeyFunction. This includes the vtable, the /// rtti data structure and the VTT. /// diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index f455827..b863aff 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -199,8 +199,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0, - /*FIXME?*/false, - /*FIXME?*/CC_Default); + /*FIXME?*/ + FunctionType::ExtInfo()); // Emit subprogram debug descriptor. if (CGDebugInfo *DI = getDebugInfo()) { @@ -211,7 +211,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // FIXME: Leaked. // CC info is ignored, hopefully? CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args, - CC_Default, false); + FunctionType::ExtInfo()); if (RetTy->isVoidType()) { // Void type; nothing to return. @@ -279,7 +279,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); // Check if we need a VTT parameter as well. - if (CGVtableInfo::needsVTTParameter(GD)) { + if (CodeGenVTables::needsVTTParameter(GD)) { // FIXME: The comment about using a fake decl above applies here too. QualType T = getContext().getPointerType(getContext().VoidPtrTy); CXXVTTDecl = diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index bd12c4a..f21350d 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -22,7 +22,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/ValueHandle.h" -#include <map> #include "CodeGenModule.h" #include "CGBlocks.h" #include "CGBuilder.h" @@ -254,6 +253,27 @@ public: } }; + /// CXXTemporariesCleanupScope - Enters a new scope for catching live + /// temporaries, all of which will be popped once the scope is exited. + class CXXTemporariesCleanupScope { + CodeGenFunction &CGF; + size_t NumLiveTemporaries; + + // DO NOT IMPLEMENT + CXXTemporariesCleanupScope(const CXXTemporariesCleanupScope &); + CXXTemporariesCleanupScope &operator=(const CXXTemporariesCleanupScope &); + + public: + explicit CXXTemporariesCleanupScope(CodeGenFunction &CGF) + : CGF(CGF), NumLiveTemporaries(CGF.LiveTemporaries.size()) { } + + ~CXXTemporariesCleanupScope() { + while (CGF.LiveTemporaries.size() > NumLiveTemporaries) + CGF.PopCXXTemporary(); + } + }; + + /// EmitCleanupBlocks - Takes the old cleanup stack size and emits the cleanup /// blocks that have been added. void EmitCleanupBlocks(size_t OldCleanupStackSize); @@ -504,30 +524,29 @@ public: /// legal to call this function even if there is no current insertion point. void FinishFunction(SourceLocation EndLoc=SourceLocation()); - /// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an - /// object pointer to alter the dynamic type of the pointer. Used by - /// GenerateCovariantThunk for building thunks. - llvm::Value *DynamicTypeAdjust(llvm::Value *V, - const ThunkAdjustment &Adjustment); - - /// GenerateThunk - Generate a thunk for the given method - llvm::Constant *GenerateThunk(llvm::Function *Fn, GlobalDecl GD, - bool Extern, - const ThunkAdjustment &ThisAdjustment); - llvm::Constant * - GenerateCovariantThunk(llvm::Function *Fn, GlobalDecl GD, - bool Extern, - const CovariantThunkAdjustment &Adjustment); - + /// GenerateThunk - Generate a thunk for the given method. + void GenerateThunk(llvm::Function *Fn, GlobalDecl GD, const ThunkInfo &Thunk); + void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type); - void InitializeVtablePtrs(const CXXRecordDecl *ClassDecl); + /// InitializeVTablePointer - Initialize the vtable pointer of the given + /// subobject. + /// + /// \param BaseIsMorallyVirtual - Whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + void InitializeVTablePointer(BaseSubobject Base, bool BaseIsMorallyVirtual, + llvm::Constant *VTable, + const CXXRecordDecl *VTableClass); + + typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; + void InitializeVTablePointers(BaseSubobject Base, bool BaseIsMorallyVirtual, + bool BaseIsNonVirtualPrimaryBase, + llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + VisitedVirtualBasesSetTy& VBases); + + void InitializeVTablePointers(const CXXRecordDecl *ClassDecl); - void InitializeVtablePtrsRecursive(const CXXRecordDecl *ClassDecl, - llvm::Constant *Vtable, - CGVtableInfo::AddrSubMap_t& AddressPoints, - llvm::Value *ThisPtr, - uint64_t Offset); void SynthesizeCXXCopyConstructor(const FunctionArgList &Args); void SynthesizeCXXCopyAssignment(const FunctionArgList &Args); @@ -1272,6 +1291,10 @@ public: /// getTrapBB - Create a basic block that will call the trap intrinsic. We'll /// generate a branch around the created basic block as necessary. llvm::BasicBlock* getTrapBB(); + + /// EmitCallArg - Emit a single call argument. + RValue EmitCallArg(const Expr *E, QualType ArgType); + private: void EmitReturnOfRValue(RValue RV, QualType Ty); @@ -1303,9 +1326,6 @@ private: /// current cleanup scope. void AddBranchFixup(llvm::BranchInst *BI); - /// EmitCallArg - Emit a single call argument. - RValue EmitCallArg(const Expr *E, QualType ArgType); - /// EmitCallArgs - Emit call arguments for a function. /// The CallArgTypeInfo parameter is used for iterating over the known /// argument types of the function being called. diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index b4b5bbd..3c872c8 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -47,7 +47,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()), - MangleCtx(C), VtableInfo(*this), Runtime(0), + MangleCtx(C), VTables(*this), Runtime(0), MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0), VMContext(M.getContext()) { @@ -79,6 +79,7 @@ void CodeGenModule::createObjCRuntime() { } void CodeGenModule::Release() { + EmitFundamentalRTTIDescriptors(); EmitDeferred(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); @@ -495,7 +496,7 @@ void CodeGenModule::EmitDeferred() { if (!DeferredVtables.empty()) { const CXXRecordDecl *RD = DeferredVtables.back(); DeferredVtables.pop_back(); - getVtableInfo().GenerateClassData(getVtableLinkage(RD), RD); + getVTables().GenerateClassData(getVtableLinkage(RD), RD); continue; } @@ -714,20 +715,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { - getVtableInfo().MaybeEmitVtable(GD); - if (MD->isVirtual() && MD->isOutOfLine() && - (!isa<CXXDestructorDecl>(D) || GD.getDtorType() != Dtor_Base)) { - if (isa<CXXDestructorDecl>(D)) { - GlobalDecl CanonGD(cast<CXXDestructorDecl>(D->getCanonicalDecl()), - GD.getDtorType()); - BuildThunksForVirtual(CanonGD); - } else { - BuildThunksForVirtual(MD->getCanonicalDecl()); - } - } - } - + if (isa<CXXMethodDecl>(D)) + getVTables().EmitVTableRelatedData(GD); + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) EmitCXXConstructor(CD, GD.getCtorType()); else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) @@ -758,7 +748,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, if (WeakRefReferences.count(Entry)) { const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl()); if (FD && !FD->hasAttr<WeakAttr>()) - Entry->setLinkage(llvm::Function::ExternalLinkage); + Entry->setLinkage(llvm::Function::ExternalLinkage); WeakRefReferences.erase(Entry); } @@ -873,7 +863,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName, if (Entry) { if (WeakRefReferences.count(Entry)) { if (D && !D->hasAttr<WeakAttr>()) - Entry->setLinkage(llvm::Function::ExternalLinkage); + Entry->setLinkage(llvm::Function::ExternalLinkage); WeakRefReferences.erase(Entry); } @@ -1255,9 +1245,9 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, if (!CI->use_empty()) CI->replaceAllUsesWith(NewCall); - // Copy any custom metadata attached with CI. - if (llvm::MDNode *DbgNode = CI->getMetadata("dbg")) - NewCall->setMetadata("dbg", DbgNode); + // Copy debug location attached to CI. + if (!CI->getDebugLoc().isUnknown()) + NewCall->setDebugLoc(CI->getDebugLoc()); CI->eraseFromParent(); } } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index febb856..3c57c0b 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -31,7 +31,6 @@ #include "llvm/ADT/StringSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ValueHandle.h" -#include <list> namespace llvm { class Module; @@ -93,8 +92,8 @@ class CodeGenModule : public BlockModule { CodeGenTypes Types; MangleContext MangleCtx; - /// VtableInfo - Holds information about C++ vtables. - CGVtableInfo VtableInfo; + /// VTables - Holds information about C++ vtables. + CodeGenVTables VTables; CGObjCRuntime* Runtime; CGDebugInfo* DebugInfo; @@ -181,7 +180,7 @@ public: llvm::Module &getModule() const { return TheModule; } CodeGenTypes &getTypes() { return Types; } MangleContext &getMangleContext() { return MangleCtx; } - CGVtableInfo &getVtableInfo() { return VtableInfo; } + CodeGenVTables &getVTables() { return VTables; } Diagnostic &getDiags() const { return Diags; } const llvm::TargetData &getTargetData() const { return TheTargetData; } llvm::LLVMContext &getLLVMContext() { return VMContext; } @@ -225,36 +224,18 @@ public: /// for the given type. llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty); - llvm::Constant *GetAddrOfThunk(GlobalDecl GD, - const ThunkAdjustment &ThisAdjustment); - llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD, - const CovariantThunkAdjustment &ThisAdjustment); - void BuildThunksForVirtual(GlobalDecl GD); - void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD); + /// GetAddrOfThunk - Get the address of the thunk for the given global decl. + llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk); /// GetWeakRefReference - Get a reference to the target of VD. llvm::Constant *GetWeakRefReference(const ValueDecl *VD); - /// BuildThunk - Build a thunk for the given method. - llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern, - const ThunkAdjustment &ThisAdjustment); - - /// BuildCoVariantThunk - Build a thunk for the given method - llvm::Constant * - BuildCovariantThunk(const GlobalDecl &GD, bool Extern, - const CovariantThunkAdjustment &Adjustment); - /// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to /// its base class. Returns null if the offset is 0. llvm::Constant * GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl); - /// ComputeThunkAdjustment - Returns the two parts required to compute the - /// offset for an object. - ThunkAdjustment ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl); - /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of /// a constant is needed consider using GetAddrOfConstantStringLiteral. @@ -523,6 +504,14 @@ private: void EmitAnnotations(void); + /// EmitFundamentalRTTIDescriptor - Emit the RTTI descriptors for the + /// given type. + void EmitFundamentalRTTIDescriptor(QualType Type); + + /// EmitFundamentalRTTIDescriptors - Emit the RTTI descriptors for the + /// builtin types. + void EmitFundamentalRTTIDescriptors(); + /// EmitDeferred - Emit any needed decls for which code generation /// was deferred. void EmitDeferred(void); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 4feca4d..f53dd83 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "CodeGenTypes.h" +#include "CGCall.h" +#include "CGRecordLayout.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" @@ -20,10 +22,6 @@ #include "llvm/DerivedTypes.h" #include "llvm/Module.h" #include "llvm/Target/TargetData.h" - -#include "CGCall.h" -#include "CGRecordLayoutBuilder.h" - using namespace clang; using namespace CodeGen; @@ -400,7 +398,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { /// ConvertTagDeclType - Lay out a tagged decl type like struct or union or /// enum. const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { - // TagDecl's are not necessarily unique, instead use the (clang) // type connected to the decl. const Type *Key = @@ -449,7 +446,7 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { } // Layout fields. - CGRecordLayout *Layout = CGRecordLayoutBuilder::ComputeLayout(*this, RD); + CGRecordLayout *Layout = ComputeRecordLayout(RD); CGRecordLayouts[Key] = Layout; const llvm::Type *ResultType = Layout->getLLVMType(); @@ -462,42 +459,11 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { return ResultHolder.get(); } -/// getLLVMFieldNo - Return llvm::StructType element number -/// that corresponds to the field FD. -unsigned CodeGenTypes::getLLVMFieldNo(const FieldDecl *FD) { - assert(!FD->isBitField() && "Don't use getLLVMFieldNo on bit fields!"); - - llvm::DenseMap<const FieldDecl*, unsigned>::iterator I = FieldInfo.find(FD); - assert (I != FieldInfo.end() && "Unable to find field info"); - return I->second; -} - -/// addFieldInfo - Assign field number to field FD. -void CodeGenTypes::addFieldInfo(const FieldDecl *FD, unsigned No) { - FieldInfo[FD] = No; -} - -/// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field FD. -CodeGenTypes::BitFieldInfo CodeGenTypes::getBitFieldInfo(const FieldDecl *FD) { - llvm::DenseMap<const FieldDecl *, BitFieldInfo>::iterator - I = BitFields.find(FD); - assert (I != BitFields.end() && "Unable to find bitfield info"); - return I->second; -} - -/// addBitFieldInfo - Assign a start bit and a size to field FD. -void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, - unsigned Start, unsigned Size) { - BitFields.insert(std::make_pair(FD, BitFieldInfo(FieldNo, Start, Size))); -} - /// getCGRecordLayout - Return record layout info for the given llvm::Type. const CGRecordLayout & -CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const { +CodeGenTypes::getCGRecordLayout(const RecordDecl *TD) const { const Type *Key = Context.getTagDeclType(TD).getTypePtr(); - llvm::DenseMap<const Type*, CGRecordLayout *>::const_iterator I - = CGRecordLayouts.find(Key); - assert (I != CGRecordLayouts.end() - && "Unable to find record layout information for type"); - return *I->second; + const CGRecordLayout *Layout = CGRecordLayouts.lookup(Key); + assert(Layout && "Unable to find record layout information for type"); + return *Layout; } diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index b2912ef..9b74106d 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -16,7 +16,6 @@ #include "llvm/Module.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallSet.h" #include <vector> #include "CGCall.h" @@ -52,37 +51,9 @@ namespace clang { typedef CanQual<Type> CanQualType; namespace CodeGen { + class CGRecordLayout; class CodeGenTypes; - /// CGRecordLayout - This class handles struct and union layout info while - /// lowering AST types to LLVM types. - class CGRecordLayout { - CGRecordLayout(); // DO NOT IMPLEMENT - - /// LLVMType - The LLVMType corresponding to this record layout. - const llvm::Type *LLVMType; - - /// ContainsPointerToDataMember - Whether one of the fields in this record - /// layout is a pointer to data member, or a struct that contains pointer to - /// data member. - bool ContainsPointerToDataMember; - - public: - CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember) - : LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) { } - - /// getLLVMType - Return llvm type associated with this record. - const llvm::Type *getLLVMType() const { - return LLVMType; - } - - /// containsPointerToDataMember - Whether this struct contains pointers to - /// data members. - bool containsPointerToDataMember() const { - return ContainsPointerToDataMember; - } - }; - /// CodeGenTypes - This class organizes the cross-module state that is used /// while lowering AST types to LLVM types. class CodeGenTypes { @@ -107,32 +78,12 @@ class CodeGenTypes { /// CGRecordLayouts - This maps llvm struct type with corresponding /// record layout info. - /// FIXME : If CGRecordLayout is less than 16 bytes then use - /// inline it in the map. llvm::DenseMap<const Type*, CGRecordLayout *> CGRecordLayouts; - /// FieldInfo - This maps struct field with corresponding llvm struct type - /// field no. This info is populated by record organizer. - llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo; - /// FunctionInfos - Hold memoized CGFunctionInfo results. llvm::FoldingSet<CGFunctionInfo> FunctionInfos; -public: - struct BitFieldInfo { - BitFieldInfo(unsigned FieldNo, - unsigned Start, - unsigned Size) - : FieldNo(FieldNo), Start(Start), Size(Size) {} - - unsigned FieldNo; - unsigned Start; - unsigned Size; - }; - private: - llvm::DenseMap<const FieldDecl *, BitFieldInfo> BitFields; - /// TypeCache - This map keeps cache of llvm::Types (through PATypeHolder) /// and maps llvm::Types to corresponding clang::Type. llvm::PATypeHolder is /// used instead of llvm::Type because it allows us to bypass potential @@ -178,11 +129,7 @@ public: /// and/or incomplete argument types, this will return the opaque type. const llvm::Type *GetFunctionTypeForVtable(const CXXMethodDecl *MD); - const CGRecordLayout &getCGRecordLayout(const TagDecl*) const; - - /// getLLVMFieldNo - Return llvm::StructType element number - /// that corresponds to the field FD. - unsigned getLLVMFieldNo(const FieldDecl *FD); + const CGRecordLayout &getCGRecordLayout(const RecordDecl*) const; /// UpdateCompletedType - When we find the full definition for a TagDecl, /// replace the 'opaque' type we previously made for it if applicable. @@ -202,7 +149,7 @@ public: const CGFunctionInfo &getFunctionInfo(const CallArgList &Args, const FunctionType *Ty) { return getFunctionInfo(Ty->getResultType(), Args, - Ty->getCallConv(), Ty->getNoReturnAttr()); + Ty->getExtInfo()); } const CGFunctionInfo &getFunctionInfo(CanQual<FunctionProtoType> Ty); const CGFunctionInfo &getFunctionInfo(CanQual<FunctionNoProtoType> Ty); @@ -216,33 +163,22 @@ public: /// specified, the "C" calling convention will be used. const CGFunctionInfo &getFunctionInfo(QualType ResTy, const CallArgList &Args, - CallingConv CC, - bool NoReturn); + const FunctionType::ExtInfo &Info); const CGFunctionInfo &getFunctionInfo(QualType ResTy, const FunctionArgList &Args, - CallingConv CC, - bool NoReturn); + const FunctionType::ExtInfo &Info); /// Retrieves the ABI information for the given function signature. /// /// \param ArgTys - must all actually be canonical as params const CGFunctionInfo &getFunctionInfo(CanQualType RetTy, const llvm::SmallVectorImpl<CanQualType> &ArgTys, - CallingConv CC, - bool NoReturn); + const FunctionType::ExtInfo &Info); -public: // These are internal details of CGT that shouldn't be used externally. - /// addFieldInfo - Assign field number to field FD. - void addFieldInfo(const FieldDecl *FD, unsigned FieldNo); - - /// addBitFieldInfo - Assign a start bit and a size to field FD. - void addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, - unsigned Start, unsigned Size); - - /// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field - /// FD. - BitFieldInfo getBitFieldInfo(const FieldDecl *FD); + /// \brief Compute a new LLVM record layout object for the given record. + CGRecordLayout *ComputeRecordLayout(const RecordDecl *D); +public: // These are internal details of CGT that shouldn't be used externally. /// ConvertTagDeclType - Lay out a tagged decl type like struct or union or /// enum. const llvm::Type *ConvertTagDeclType(const TagDecl *TD); diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index f2a73f1..077db7c 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -102,7 +102,7 @@ public: llvm::raw_svector_ostream &getStream() { return Out; } void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z"); - void mangleCallOffset(const ThunkAdjustment &Adjustment); + void mangleCallOffset(int64_t NonVirtual, int64_t Virtual); void mangleNumber(int64_t Number); void mangleFunctionEncoding(const FunctionDecl *FD); void mangleName(const NamedDecl *ND); @@ -439,23 +439,23 @@ void CXXNameMangler::mangleNumber(int64_t Number) { Out << Number; } -void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) { +void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) { // <call-offset> ::= h <nv-offset> _ // ::= v <v-offset> _ // <nv-offset> ::= <offset number> # non-virtual base override // <v-offset> ::= <offset number> _ <virtual offset number> // # virtual base override, with vcall offset - if (!Adjustment.Virtual) { + if (!Virtual) { Out << 'h'; - mangleNumber(Adjustment.NonVirtual); + mangleNumber(NonVirtual); Out << '_'; return; } Out << 'v'; - mangleNumber(Adjustment.NonVirtual); + mangleNumber(NonVirtual); Out << '_'; - mangleNumber(Adjustment.Virtual); + mangleNumber(Virtual); Out << '_'; } @@ -1131,15 +1131,20 @@ void CXXNameMangler::mangleType(const ComplexType *T) { } // GNU extension: vector types +// <type> ::= <vector-type> +// <vector-type> ::= Dv <positive dimension number> _ <element type> +// ::= Dv [<dimension expression>] _ <element type> void CXXNameMangler::mangleType(const VectorType *T) { - Out << "U8__vector"; + Out << "Dv" << T->getNumElements() << '_'; mangleType(T->getElementType()); } void CXXNameMangler::mangleType(const ExtVectorType *T) { mangleType(static_cast<const VectorType*>(T)); } void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { - Out << "U8__vector"; + Out << "Dv"; + mangleExpression(T->getSizeExpr()); + Out << '_'; mangleType(T->getElementType()); } @@ -1159,7 +1164,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { mangleName(TD, T->getArgs(), T->getNumArgs()); } -void CXXNameMangler::mangleType(const TypenameType *T) { +void CXXNameMangler::mangleType(const DependentNameType *T) { // Typename types are always nested Out << 'N'; mangleUnresolvedScope(T->getQualifier()); @@ -1451,8 +1456,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) { // It isn't clear that we ever actually want to have such a // nested-name-specifier; why not just represent it as a typename type? if (!QTy && NNS->getAsIdentifier() && NNS->getPrefix()) { - QTy = getASTContext().getTypenameType(NNS->getPrefix(), - NNS->getAsIdentifier()) + QTy = getASTContext().getDependentNameType(ETK_Typename, + NNS->getPrefix(), + NNS->getAsIdentifier()) .getTypePtr(); } assert(QTy && "Qualifier was not type!"); @@ -1862,52 +1868,50 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, Mangler.mangle(D); } -/// \brief Mangles the a thunk with the offset n for the declaration D and -/// emits that name to the given output stream. -void MangleContext::mangleThunk(const FunctionDecl *FD, - const ThunkAdjustment &ThisAdjustment, +void MangleContext::mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, llvm::SmallVectorImpl<char> &Res) { - assert(!isa<CXXDestructorDecl>(FD) && - "Use mangleCXXDtor for destructor decls!"); - // <special-name> ::= T <call-offset> <base encoding> // # base is the nominal target function of thunk + // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> + // # base is the nominal target function of thunk + // # first call-offset is 'this' adjustment + // # second call-offset is result adjustment + + assert(!isa<CXXDestructorDecl>(MD) && + "Use mangleCXXDtor for destructor decls!"); + CXXNameMangler Mangler(*this, Res); Mangler.getStream() << "_ZT"; - Mangler.mangleCallOffset(ThisAdjustment); - Mangler.mangleFunctionEncoding(FD); -} - -void MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *D, - CXXDtorType Type, - const ThunkAdjustment &ThisAdjustment, - llvm::SmallVectorImpl<char> &Res) { + if (!Thunk.Return.isEmpty()) + Mangler.getStream() << 'c'; + + // Mangle the 'this' pointer adjustment. + Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset); + + // Mangle the return pointer adjustment if there is one. + if (!Thunk.Return.isEmpty()) + Mangler.mangleCallOffset(Thunk.Return.NonVirtual, + Thunk.Return.VBaseOffsetOffset); + + Mangler.mangleFunctionEncoding(MD); +} + +void +MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + llvm::SmallVectorImpl<char> &Res) { // <special-name> ::= T <call-offset> <base encoding> // # base is the nominal target function of thunk - CXXNameMangler Mangler(*this, Res, D, Type); + + CXXNameMangler Mangler(*this, Res, DD, Type); Mangler.getStream() << "_ZT"; - Mangler.mangleCallOffset(ThisAdjustment); - Mangler.mangleFunctionEncoding(D); -} -/// \brief Mangles the a covariant thunk for the declaration D and emits that -/// name to the given output stream. -void -MangleContext::mangleCovariantThunk(const FunctionDecl *FD, - const CovariantThunkAdjustment& Adjustment, - llvm::SmallVectorImpl<char> &Res) { - assert(!isa<CXXDestructorDecl>(FD) && - "No such thing as a covariant thunk for a destructor!"); + // Mangle the 'this' pointer adjustment. + Mangler.mangleCallOffset(ThisAdjustment.NonVirtual, + ThisAdjustment.VCallOffsetOffset); - // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> - // # base is the nominal target function of thunk - // # first call-offset is 'this' adjustment - // # second call-offset is result adjustment - CXXNameMangler Mangler(*this, Res); - Mangler.getStream() << "_ZTc"; - Mangler.mangleCallOffset(Adjustment.ThisAdjustment); - Mangler.mangleCallOffset(Adjustment.ReturnAdjustment); - Mangler.mangleFunctionEncoding(FD); + Mangler.mangleFunctionEncoding(DD); } /// mangleGuardVariable - Returns the mangled name for a guard variable diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 62656b9..91a5e97 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -28,13 +28,14 @@ namespace clang { class ASTContext; class CXXConstructorDecl; class CXXDestructorDecl; + class CXXMethodDecl; class FunctionDecl; class NamedDecl; class VarDecl; namespace CodeGen { - class CovariantThunkAdjustment; - class ThunkAdjustment; + struct ThisAdjustment; + struct ThunkInfo; /// MangleBuffer - a convenient class for storing a name which is /// either the result of a mangling or is a constant string with @@ -91,15 +92,12 @@ public: bool shouldMangleDeclName(const NamedDecl *D); void mangleName(const NamedDecl *D, llvm::SmallVectorImpl<char> &); - void mangleThunk(const FunctionDecl *FD, - const ThunkAdjustment &ThisAdjustment, + void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, llvm::SmallVectorImpl<char> &); - void mangleCXXDtorThunk(const CXXDestructorDecl *D, CXXDtorType Type, - const ThunkAdjustment &ThisAdjustment, + void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, llvm::SmallVectorImpl<char> &); - void mangleCovariantThunk(const FunctionDecl *FD, - const CovariantThunkAdjustment& Adjustment, - llvm::SmallVectorImpl<char> &); void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &); void mangleCXXVtable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &); void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &); diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 60d8e9c..7efcd8a 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -10,8 +10,8 @@ add_clang_library(clangDriver DriverOptions.cpp HostInfo.cpp Job.cpp - OptTable.cpp Option.cpp + OptTable.cpp Phases.cpp Tool.cpp ToolChain.cpp diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index acfff38..921147f 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -45,7 +45,8 @@ using namespace clang; Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, llvm::StringRef _DefaultHostTriple, llvm::StringRef _DefaultImageName, - bool IsProduction, Diagnostic &_Diags) + bool IsProduction, bool CXXIsProduction, + Diagnostic &_Diags) : Opts(createDriverOptTable()), Diags(_Diags), Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName), @@ -66,7 +67,8 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, CCCClangArchs.insert(llvm::Triple::x86_64); CCCClangArchs.insert(llvm::Triple::arm); - CCCUseClangCXX = false; + if (!CXXIsProduction) + CCCUseClangCXX = false; } // Compute the path to the resource directory. @@ -172,6 +174,8 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { HostTriple = A->getValue(*Args); if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir)) Dir = A->getValue(*Args); + if (const Arg *A = Args->getLastArg(options::OPT_B)) + PrefixDir = A->getValue(*Args); Host = GetHostInfo(HostTriple); @@ -1088,6 +1092,15 @@ const char *Driver::GetNamedOutputPath(Compilation &C, } std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { + // Respect a limited subset of the '-Bprefix' functionality in GCC by + // attempting to use this prefix when lokup up program paths. + if (!PrefixDir.empty()) { + llvm::sys::Path P(PrefixDir); + P.appendComponent(Name); + if (P.exists()) + return P.str(); + } + const ToolChain::path_list &List = TC.getFilePaths(); for (ToolChain::path_list::const_iterator it = List.begin(), ie = List.end(); it != ie; ++it) { @@ -1102,6 +1115,15 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC, bool WantFile) const { + // Respect a limited subset of the '-Bprefix' functionality in GCC by + // attempting to use this prefix when lokup up program paths. + if (!PrefixDir.empty()) { + llvm::sys::Path P(PrefixDir); + P.appendComponent(Name); + if (WantFile ? P.exists() : P.canExecute()) + return P.str(); + } + const ToolChain::path_list &List = TC.getProgramPaths(); for (ToolChain::path_list::const_iterator it = List.begin(), ie = List.end(); it != ie; ++it) { diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp index d8e086d..d9e2e37 100644 --- a/lib/Driver/HostInfo.cpp +++ b/lib/Driver/HostInfo.cpp @@ -144,13 +144,15 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args, TCTriple.setArch(Arch); // If we recognized the arch, match it to the toolchains we support. - if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { + const char *UseNewToolChain = ::getenv("CCC_ENABLE_NEW_DARWIN_TOOLCHAIN"); + if (UseNewToolChain || + Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) { + TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion); + } 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, DarwinVersion, GCCVersion); - } else if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) - TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion); - else + } else TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple); } diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 1c34df0..2a37991 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -56,6 +56,35 @@ static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { << A->getAsString(Args) << "-static"; } +// Quote target names for inclusion in GNU Make dependency files. +// Only the characters '$', '#', ' ', '\t' are quoted. +static void QuoteTarget(llvm::StringRef Target, + llvm::SmallVectorImpl<char> &Res) { + for (unsigned i = 0, e = Target.size(); i != e; ++i) { + switch (Target[i]) { + case ' ': + case '\t': + // Escape the preceding backslashes + for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j) + Res.push_back('\\'); + + // Escape the space/tab + Res.push_back('\\'); + break; + case '$': + Res.push_back('$'); + break; + case '#': + Res.push_back('\\'); + break; + default: + break; + } + + Res.push_back(Target[i]); + } +} + void Clang::AddPreprocessingOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, @@ -91,9 +120,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, CmdArgs.push_back("-dependency-file"); CmdArgs.push_back(DepFile); - // Add an -MT option if the user didn't specify their own. - // - // FIXME: This should use -MQ, when we support it. + // Add a default target if one wasn't specified. if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) { const char *DepTarget; @@ -114,7 +141,9 @@ void Clang::AddPreprocessingOptions(const Driver &D, } CmdArgs.push_back("-MT"); - CmdArgs.push_back(DepTarget); + llvm::SmallString<128> Quoted; + QuoteTarget(DepTarget, Quoted); + CmdArgs.push_back(Args.MakeArgString(Quoted)); } if (A->getOption().matches(options::OPT_M) || @@ -123,7 +152,25 @@ void Clang::AddPreprocessingOptions(const Driver &D, } Args.AddLastArg(CmdArgs, options::OPT_MP); - Args.AddAllArgs(CmdArgs, options::OPT_MT); + + // Convert all -MQ <target> args to -MT <quoted target> + for (arg_iterator it = Args.filtered_begin(options::OPT_MT, + options::OPT_MQ), + ie = Args.filtered_end(); it != ie; ++it) { + + it->claim(); + + if (it->getOption().matches(options::OPT_MQ)) { + CmdArgs.push_back("-MT"); + llvm::SmallString<128> Quoted; + QuoteTarget(it->getValue(Args), Quoted); + CmdArgs.push_back(Args.MakeArgString(Quoted)); + + // -MT flag - no change + } else { + it->render(Args, CmdArgs); + } + } // Add -i* options, and automatically translate to // -include-pch/-include-pth for transparent PCH support. It's @@ -796,6 +843,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("plist"); + // Disable the presentation of standard compiler warnings when + // using --analyze. We only want to show static analyzer diagnostics + // or frontend errors. + CmdArgs.push_back("-w"); + // Add -Xanalyzer arguments when running as analyzer. Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); } @@ -925,7 +977,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_MG)) || - (Unsupported = Args.getLastArg(options::OPT_MQ)) || (Unsupported = Args.getLastArg(options::OPT_iframework)) || (Unsupported = Args.getLastArg(options::OPT_fshort_enums))) D.Diag(clang::diag::err_drv_clang_unsupported) @@ -943,6 +994,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-g"); Args.AddLastArg(CmdArgs, options::OPT_nostdinc); + Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); // Pass the path to compiler resource files. @@ -1701,6 +1753,7 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args, if (!Args.hasArg(options::OPT_Q)) CmdArgs.push_back("-quiet"); Args.AddAllArgs(CmdArgs, options::OPT_nostdinc); + Args.AddAllArgs(CmdArgs, options::OPT_nostdincxx); Args.AddLastArg(CmdArgs, options::OPT_v); Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F); Args.AddLastArg(CmdArgs, options::OPT_P); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 935c415..7243f70 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -378,7 +378,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, // FIXME: We shouldn't have to pass in the path info. driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(), - "a.out", false, Diags); + "a.out", false, false, Diags); // Don't check that inputs exist, they have been remapped. TheDriver.setCheckInputsExist(false); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 7b4932d..879e9f6 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -29,6 +29,7 @@ #include "llvm/LLVMContext.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Support/Timer.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" @@ -479,6 +480,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { if (getFrontendOpts().ShowTimers) createFrontendTimer(); + if (getFrontendOpts().ShowStats) + llvm::EnableStatistics(); + for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { const std::string &InFile = getFrontendOpts().Inputs[i].second; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 6e18f34..dc2c6bf 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -436,6 +436,8 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, } if (!Opts.UseStandardIncludes) Res.push_back("-nostdinc"); + if (!Opts.UseStandardCXXIncludes) + Res.push_back("-nostdinc++"); if (Opts.Verbose) Res.push_back("-v"); } @@ -1014,6 +1016,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Opts.Verbose = Args.hasArg(OPT_v); Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); + Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx); Opts.ResourceDir = getLastArgValue(Args, OPT_resource_dir); // Add -I... and -F... options in order. diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index de2b056..14aee35 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -48,14 +48,15 @@ public: IncludeSystemHeaders(Opts.IncludeSystemHeaders), PhonyTarget(Opts.UsePhonyTargets) {} - ~DependencyFileCallback() { + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType); + + virtual void EndOfMainFile() { OutputDependencyFile(); OS->flush(); delete OS; + OS = 0; } - - virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType); }; } diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp index 0b04cf2..20d452e 100644 --- a/lib/Frontend/FixItRewriter.cpp +++ b/lib/Frontend/FixItRewriter.cpp @@ -93,7 +93,7 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, // completely ignore it, even if it's an error: fix-it locations // are meant to perform specific fix-ups even in the presence of // other errors. - if (Info.getNumCodeModificationHints() == 0) + if (Info.getNumFixItHints() == 0) return; // See if the location of the error is one that matches what the @@ -122,10 +122,10 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, // Make sure that we can perform all of the modifications we // in this diagnostic. - bool CanRewrite = Info.getNumCodeModificationHints() > 0; - for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints(); + bool CanRewrite = Info.getNumFixItHints() > 0; + for (unsigned Idx = 0, Last = Info.getNumFixItHints(); Idx < Last; ++Idx) { - const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx); + const FixItHint &Hint = Info.getFixItHint(Idx); if (Hint.RemoveRange.isValid() && Rewrite.getRangeSize(Hint.RemoveRange) == -1) { CanRewrite = false; @@ -140,7 +140,7 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, } if (!CanRewrite) { - if (Info.getNumCodeModificationHints() > 0) + if (Info.getNumFixItHints() > 0) Diag(Info.getLocation(), diag::note_fixit_in_macro); // If this was an error, refuse to perform any rewriting. @@ -152,9 +152,9 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, } bool Failed = false; - for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints(); + for (unsigned Idx = 0, Last = Info.getNumFixItHints(); Idx < Last; ++Idx) { - const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx); + const FixItHint &Hint = Info.getFixItHint(Idx); if (!Hint.RemoveRange.isValid()) { // We're adding code. if (Rewrite.InsertTextBefore(Hint.InsertionLoc, Hint.CodeToInsert)) diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 66df7a6..110612d 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -169,6 +169,10 @@ void FrontendAction::EndSourceFile() { CI.setASTContext(0); } + // Inform the preprocessor we are done. + if (CI.hasPreprocessor()) + CI.getPreprocessor().EndSourceFile(); + if (CI.getFrontendOpts().ShowStats) { llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n"; CI.getPreprocessor().PrintStats(); diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp index da99cb8..022a34d 100644 --- a/lib/Frontend/HTMLDiagnostics.cpp +++ b/lib/Frontend/HTMLDiagnostics.cpp @@ -484,8 +484,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, // FIXME: This code is disabled because it seems to mangle the HTML // output. I'm leaving it here because it's generally the right idea, // but needs some help from someone more familiar with the rewriter. - for (const CodeModificationHint *Hint = P.code_modifications_begin(), - *HintEnd = P.code_modifications_end(); + for (const FixItHint *Hint = P.fixit_begin(), *HintEnd = P.fixit_end(); Hint != HintEnd; ++Hint) { if (Hint->RemoveRange.isValid()) { HighlightRange(R, LPosInfo.first, Hint->RemoveRange, diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index cd749d2..9f5bced 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -82,7 +82,8 @@ public: /// AddDefaultSystemIncludePaths - Adds the default system include paths so /// that e.g. stdio.h is found. void AddDefaultSystemIncludePaths(const LangOptions &Lang, - const llvm::Triple &triple); + const llvm::Triple &triple, + bool UseStandardCXXIncludes); /// Realize - Merges all search path lists into one list and send it to /// HeaderSearch. @@ -594,8 +595,9 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl } void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, - const llvm::Triple &triple) { - if (Lang.CPlusPlus) + const llvm::Triple &triple, + bool UseStandardCXXIncludes) { + if (Lang.CPlusPlus && UseStandardCXXIncludes) AddDefaultCPlusPlusIncludePaths(triple); AddDefaultCIncludePaths(triple); @@ -765,7 +767,8 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, } if (HSOpts.UseStandardIncludes) - Init.AddDefaultSystemIncludePaths(Lang, Triple); + Init.AddDefaultSystemIncludePaths(Lang, Triple, + HSOpts.UseStandardCXXIncludes); Init.Realize(); } diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index e659ff0..6d39952 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -905,11 +905,18 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { return Failure; } - if (Record.size() < 8) { + if (Record.size() < 10) { Error("source location entry is incorrect"); return Failure; } + if ((off_t)Record[4] != File->getSize() || + (time_t)Record[5] != File->getModificationTime()) { + Diag(diag::err_fe_pch_file_modified) + << Filename; + return Failure; + } + FileID FID = SourceMgr.createFileID(File, SourceLocation::getFromRawEncoding(Record[1]), (SrcMgr::CharacteristicKind)Record[2], @@ -920,10 +927,10 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { // Reconstruct header-search information for this file. HeaderFileInfo HFI; - HFI.isImport = Record[4]; - HFI.DirInfo = Record[5]; - HFI.NumIncludes = Record[6]; - HFI.ControllingMacroID = Record[7]; + HFI.isImport = Record[6]; + HFI.DirInfo = Record[7]; + HFI.NumIncludes = Record[8]; + HFI.ControllingMacroID = Record[9]; if (Listener) Listener->ReadHeaderFileInfo(HFI, File->getUID()); break; @@ -2068,20 +2075,21 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { } case pch::TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 3) { + if (Record.size() != 4) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = GetType(Record[0]); - return Context->getFunctionNoProtoType(ResultType, Record[1], - (CallingConv)Record[2]); + FunctionType::ExtInfo Info(Record[1], Record[2], (CallingConv)Record[3]); + return Context->getFunctionNoProtoType(ResultType, Info); } case pch::TYPE_FUNCTION_PROTO: { QualType ResultType = GetType(Record[0]); bool NoReturn = Record[1]; - CallingConv CallConv = (CallingConv)Record[2]; - unsigned Idx = 3; + unsigned RegParm = Record[2]; + CallingConv CallConv = (CallingConv)Record[3]; + unsigned Idx = 4; unsigned NumParams = Record[Idx++]; llvm::SmallVector<QualType, 16> ParamTypes; for (unsigned I = 0; I != NumParams; ++I) @@ -2097,7 +2105,9 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, isVariadic, Quals, hasExceptionSpec, hasAnyExceptionSpec, NumExceptions, - Exceptions.data(), NoReturn, CallConv); + Exceptions.data(), + FunctionType::ExtInfo(NoReturn, RegParm, + CallConv)); } case pch::TYPE_UNRESOLVED_USING: @@ -2341,7 +2351,7 @@ void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } -void TypeLocReader::VisitTypenameTypeLoc(TypenameTypeLoc TL) { +void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 4752cd3..4dd8dc3 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -141,9 +141,11 @@ void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) { void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { Writer.AddTypeRef(T->getResultType(), Record); - Record.push_back(T->getNoReturnAttr()); + FunctionType::ExtInfo C = T->getExtInfo(); + Record.push_back(C.getNoReturn()); + Record.push_back(C.getRegParm()); // FIXME: need to stabilize encoding of calling convention... - Record.push_back(T->getCallConv()); + Record.push_back(C.getCC()); } void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { @@ -404,7 +406,7 @@ void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } -void TypeLocWriter::VisitTypenameTypeLoc(TypenameTypeLoc TL) { +void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { @@ -921,6 +923,9 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives + // FileEntry fields. + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time // HeaderFileInfo fields. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isImport Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // DirInfo @@ -1063,6 +1068,10 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // 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()); + // Emit header-search information associated with this file. HeaderFileInfo HFI; HeaderSearch &HS = PP.getHeaderSearchInfo(); diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 79aecce..cba9298 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -2262,8 +2262,8 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() { QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size(), false /*isVariadic*/, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), SelGetUidIdent, getFuncType, 0, @@ -2359,8 +2359,8 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() { QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size(), false, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, @@ -2380,8 +2380,8 @@ void RewriteObjC::SynthMsgSendFunctionDecl() { QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size(), true /*isVariadic*/, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, @@ -2404,8 +2404,8 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() { QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size(), true /*isVariadic*/, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, @@ -2425,8 +2425,8 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() { QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size(), true /*isVariadic*/, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, @@ -2451,8 +2451,8 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size(), true /*isVariadic*/, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, @@ -2472,8 +2472,8 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() { QualType msgSendType = Context->getFunctionType(Context->DoubleTy, &ArgTys[0], ArgTys.size(), true /*isVariadic*/, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, @@ -2488,8 +2488,8 @@ void RewriteObjC::SynthGetClassFunctionDecl() { QualType getClassType = Context->getFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size(), false /*isVariadic*/, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), getClassIdent, getClassType, 0, @@ -2505,8 +2505,8 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() { QualType getClassType = Context->getFunctionType(Context->getObjCClassType(), &ArgTys[0], ArgTys.size(), false /*isVariadic*/, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), getSuperClassIdent, getClassType, 0, @@ -2521,8 +2521,8 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() { QualType getClassType = Context->getFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size(), false /*isVariadic*/, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), getClassIdent, getClassType, 0, @@ -2964,8 +2964,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, &ArgTypes[0], ArgTypes.size(), // If we don't have a method decl, force a variadic cast. Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); castType = Context->getPointerType(castType); cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, cast); @@ -2995,8 +2995,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, castType = Context->getFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false, 0, - false, false, 0, 0, false, - CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); castType = Context->getPointerType(castType); cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, cast); @@ -4547,7 +4547,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { QualType PtrToFuncCastType = Context->getFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size(), false/*no variadic*/, 0, false, false, 0, 0, - false, CC_Default); + FunctionType::ExtInfo()); PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); @@ -5673,4 +5673,3 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) { } OutFile->flush(); } - diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 24d51e2..4e91f8d 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -276,7 +276,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, SourceRange *Ranges, unsigned NumRanges, SourceManager &SM, - const CodeModificationHint *Hints, + const FixItHint *Hints, unsigned NumHints, unsigned Columns) { assert(LangOpts && "Unexpected diagnostic outside source file processing"); @@ -409,7 +409,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, std::string FixItInsertionLine; if (NumHints && DiagOpts->ShowFixits) { - for (const CodeModificationHint *Hint = Hints, *LastHint = Hints + NumHints; + for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints; Hint != LastHint; ++Hint) { if (Hint->InsertionLoc.isValid()) { // We have an insertion hint. Determine whether the inserted @@ -833,7 +833,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, if (DiagOpts->ShowCarets && Info.getLocation().isValid() && ((LastLoc != Info.getLocation()) || Info.getNumRanges() || (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || - Info.getNumCodeModificationHints())) { + Info.getNumFixItHints())) { // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. LastLoc = Info.getLocation(); LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); @@ -845,9 +845,9 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, for (unsigned i = 0; i != NumRanges; ++i) Ranges[i] = Info.getRange(i); - unsigned NumHints = Info.getNumCodeModificationHints(); + unsigned NumHints = Info.getNumFixItHints(); for (unsigned idx = 0; idx < NumHints; ++idx) { - const CodeModificationHint &Hint = Info.getCodeModificationHint(idx); + const FixItHint &Hint = Info.getFixItHint(idx); if (Hint.RemoveRange.isValid()) { assert(NumRanges < 20 && "Out of space"); Ranges[NumRanges++] = Hint.RemoveRange; @@ -855,8 +855,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, } EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), - Info.getCodeModificationHints(), - Info.getNumCodeModificationHints(), + Info.getFixItHints(), + Info.getNumFixItHints(), DiagOpts->MessageLength); } diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h index b09a627..6b9dd2a 100644 --- a/lib/Headers/emmintrin.h +++ b/lib/Headers/emmintrin.h @@ -36,417 +36,417 @@ typedef long long __m128i __attribute__((__vector_size__(16))); typedef short __v8hi __attribute__((__vector_size__(16))); typedef char __v16qi __attribute__((__vector_size__(16))); -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_add_sd(__m128d a, __m128d b) { a[0] += b[0]; return a; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_add_pd(__m128d a, __m128d b) { return a + b; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_sub_sd(__m128d a, __m128d b) { a[0] -= b[0]; return a; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_sub_pd(__m128d a, __m128d b) { return a - b; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_mul_sd(__m128d a, __m128d b) { a[0] *= b[0]; return a; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_mul_pd(__m128d a, __m128d b) { return a * b; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_div_sd(__m128d a, __m128d b) { a[0] /= b[0]; return a; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_div_pd(__m128d a, __m128d b) { return a / b; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_sqrt_sd(__m128d a, __m128d b) { __m128d c = __builtin_ia32_sqrtsd(b); return (__m128d) { c[0], a[1] }; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_sqrt_pd(__m128d a) { return __builtin_ia32_sqrtpd(a); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_min_sd(__m128d a, __m128d b) { return __builtin_ia32_minsd(a, b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_min_pd(__m128d a, __m128d b) { return __builtin_ia32_minpd(a, b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_max_sd(__m128d a, __m128d b) { return __builtin_ia32_maxsd(a, b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_max_pd(__m128d a, __m128d b) { return __builtin_ia32_maxpd(a, b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_and_pd(__m128d a, __m128d b) { return (__m128d)((__v4si)a & (__v4si)b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_andnot_pd(__m128d a, __m128d b) { return (__m128d)(~(__v4si)a & (__v4si)b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_or_pd(__m128d a, __m128d b) { return (__m128d)((__v4si)a | (__v4si)b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_xor_pd(__m128d a, __m128d b) { return (__m128d)((__v4si)a ^ (__v4si)b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(a, b, 0); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmplt_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(a, b, 1); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmple_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(a, b, 2); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(b, a, 1); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpge_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(b, a, 2); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpord_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(a, b, 7); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpunord_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(a, b, 3); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpneq_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(a, b, 4); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpnlt_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(a, b, 5); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpnle_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(a, b, 6); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpngt_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(b, a, 5); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpnge_pd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmppd(b, a, 6); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(a, b, 0); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmplt_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(a, b, 1); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmple_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(a, b, 2); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(b, a, 1); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpge_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(b, a, 2); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpord_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(a, b, 7); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpunord_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(a, b, 3); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpneq_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(a, b, 4); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpnlt_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(a, b, 5); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpnle_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(a, b, 6); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpngt_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(b, a, 5); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cmpnge_sd(__m128d a, __m128d b) { return (__m128d)__builtin_ia32_cmpsd(b, a, 6); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comieq_sd(__m128d a, __m128d b) { return __builtin_ia32_comisdeq(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comilt_sd(__m128d a, __m128d b) { return __builtin_ia32_comisdlt(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comile_sd(__m128d a, __m128d b) { return __builtin_ia32_comisdle(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comigt_sd(__m128d a, __m128d b) { return __builtin_ia32_comisdgt(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comineq_sd(__m128d a, __m128d b) { return __builtin_ia32_comisdneq(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomieq_sd(__m128d a, __m128d b) { return __builtin_ia32_ucomisdeq(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomilt_sd(__m128d a, __m128d b) { return __builtin_ia32_ucomisdlt(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomile_sd(__m128d a, __m128d b) { return __builtin_ia32_ucomisdle(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomigt_sd(__m128d a, __m128d b) { return __builtin_ia32_ucomisdgt(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomineq_sd(__m128d a, __m128d b) { return __builtin_ia32_ucomisdneq(a, b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtpd_ps(__m128d a) { return __builtin_ia32_cvtpd2ps(a); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cvtps_pd(__m128 a) { return __builtin_ia32_cvtps2pd(a); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cvtepi32_pd(__m128i a) { return __builtin_ia32_cvtdq2pd((__v4si)a); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtpd_epi32(__m128d a) { return __builtin_ia32_cvtpd2dq(a); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_cvtsd_si32(__m128d a) { return __builtin_ia32_cvtsd2si(a); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtsd_ss(__m128 a, __m128d b) { a[0] = b[0]; return a; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi32_sd(__m128d a, int b) { a[0] = b; return a; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cvtss_sd(__m128d a, __m128 b) { a[0] = b[0]; return a; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvttpd_epi32(__m128d a) { return (__m128i)__builtin_ia32_cvttpd2dq(a); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_cvttsd_si32(__m128d a) { return a[0]; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cvtpd_pi32(__m128d a) { return (__m64)__builtin_ia32_cvtpd2pi(a); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cvttpd_pi32(__m128d a) { return (__m64)__builtin_ia32_cvttpd2pi(a); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cvtpi32_pd(__m64 a) { return __builtin_ia32_cvtpi2pd((__v2si)a); } -static inline double __attribute__((__always_inline__, __nodebug__)) +static __inline__ double __attribute__((__always_inline__, __nodebug__)) _mm_cvtsd_f64(__m128d a) { return a[0]; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_load_pd(double const *dp) { return *(__m128d*)dp; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_load1_pd(double const *dp) { return (__m128d){ dp[0], dp[0] }; @@ -454,542 +454,542 @@ _mm_load1_pd(double const *dp) #define _mm_load_pd1(dp) _mm_load1_pd(dp) -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadr_pd(double const *dp) { return (__m128d){ dp[1], dp[0] }; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadu_pd(double const *dp) { return __builtin_ia32_loadupd(dp); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_load_sd(double const *dp) { return (__m128d){ *dp, 0.0 }; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadh_pd(__m128d a, double const *dp) { return __builtin_shufflevector(a, *(__m128d *)dp, 0, 2); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadl_pd(__m128d a, double const *dp) { return __builtin_shufflevector(a, *(__m128d *)dp, 2, 1); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_set_sd(double w) { return (__m128d){ w, 0 }; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_set1_pd(double w) { return (__m128d){ w, w }; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_set_pd(double w, double x) { return (__m128d){ x, w }; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_setr_pd(double w, double x) { return (__m128d){ w, x }; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_setzero_pd(void) { return (__m128d){ 0, 0 }; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_move_sd(__m128d a, __m128d b) { return (__m128d){ b[0], a[1] }; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_store_sd(double *dp, __m128d a) { dp[0] = a[0]; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_store1_pd(double *dp, __m128d a) { dp[0] = a[0]; dp[1] = a[0]; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_store_pd(double *dp, __m128d a) { *(__m128d *)dp = a; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storeu_pd(double *dp, __m128d a) { __builtin_ia32_storeupd(dp, a); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storer_pd(double *dp, __m128d a) { dp[0] = a[1]; dp[1] = a[0]; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storeh_pd(double *dp, __m128d a) { dp[0] = a[1]; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storel_pd(double *dp, __m128d a) { dp[0] = a[0]; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_add_epi8(__m128i a, __m128i b) { return (__m128i)((__v16qi)a + (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_add_epi16(__m128i a, __m128i b) { return (__m128i)((__v8hi)a + (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_add_epi32(__m128i a, __m128i b) { return (__m128i)((__v4si)a + (__v4si)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_add_si64(__m64 a, __m64 b) { return a + b; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_add_epi64(__m128i a, __m128i b) { return a + b; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_adds_epi8(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_paddsb128((__v16qi)a, (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_adds_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_paddsw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_adds_epu8(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_paddusb128((__v16qi)a, (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_adds_epu16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_paddusw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_avg_epu8(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pavgb128((__v16qi)a, (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_avg_epu16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pavgw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_madd_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pmaddwd128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_max_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pmaxsw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_max_epu8(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pmaxub128((__v16qi)a, (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_min_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pminsw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_min_epu8(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pminub128((__v16qi)a, (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_mulhi_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pmulhw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_mulhi_epu16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pmulhuw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_mullo_epi16(__m128i a, __m128i b) { return (__m128i)((__v8hi)a * (__v8hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_mul_su32(__m64 a, __m64 b) { return __builtin_ia32_pmuludq((__v2si)a, (__v2si)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_mul_epu32(__m128i a, __m128i b) { return __builtin_ia32_pmuludq128((__v4si)a, (__v4si)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sad_epu8(__m128i a, __m128i b) { return __builtin_ia32_psadbw128((__v16qi)a, (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sub_epi8(__m128i a, __m128i b) { return (__m128i)((__v16qi)a - (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sub_epi16(__m128i a, __m128i b) { return (__m128i)((__v8hi)a - (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sub_epi32(__m128i a, __m128i b) { return (__m128i)((__v4si)a - (__v4si)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sub_si64(__m64 a, __m64 b) { return a - b; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sub_epi64(__m128i a, __m128i b) { return a - b; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_subs_epi8(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_psubsb128((__v16qi)a, (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_subs_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_psubsw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_subs_epu8(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_psubusb128((__v16qi)a, (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_subs_epu16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_psubusw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_and_si128(__m128i a, __m128i b) { return a & b; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_andnot_si128(__m128i a, __m128i b) { return ~a & b; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_or_si128(__m128i a, __m128i b) { return a | b; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_xor_si128(__m128i a, __m128i b) { return a ^ b; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_slli_si128(__m128i a, int imm) { return __builtin_ia32_pslldqi128(a, imm * 8); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_slli_epi16(__m128i a, int count) { return (__m128i)__builtin_ia32_psllwi128((__v8hi)a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sll_epi16(__m128i a, __m128i count) { return (__m128i)__builtin_ia32_psllw128((__v8hi)a, (__v8hi)count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_slli_epi32(__m128i a, int count) { return (__m128i)__builtin_ia32_pslldi128((__v4si)a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sll_epi32(__m128i a, __m128i count) { return (__m128i)__builtin_ia32_pslld128((__v4si)a, (__v4si)count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_slli_epi64(__m128i a, int count) { return __builtin_ia32_psllqi128(a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sll_epi64(__m128i a, __m128i count) { return __builtin_ia32_psllq128(a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_srai_epi16(__m128i a, int count) { return (__m128i)__builtin_ia32_psrawi128((__v8hi)a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sra_epi16(__m128i a, __m128i count) { return (__m128i)__builtin_ia32_psraw128((__v8hi)a, (__v8hi)count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_srai_epi32(__m128i a, int count) { return (__m128i)__builtin_ia32_psradi128((__v4si)a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sra_epi32(__m128i a, __m128i count) { return (__m128i)__builtin_ia32_psrad128((__v4si)a, (__v4si)count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_srli_si128(__m128i a, int imm) { return __builtin_ia32_psrldqi128(a, imm * 8); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_srli_epi16(__m128i a, int count) { return (__m128i)__builtin_ia32_psrlwi128((__v8hi)a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_srl_epi16(__m128i a, __m128i count) { return (__m128i)__builtin_ia32_psrlw128((__v8hi)a, (__v8hi)count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_srli_epi32(__m128i a, int count) { return (__m128i)__builtin_ia32_psrldi128((__v4si)a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_srl_epi32(__m128i a, __m128i count) { return (__m128i)__builtin_ia32_psrld128((__v4si)a, (__v4si)count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_srli_epi64(__m128i a, int count) { return __builtin_ia32_psrlqi128(a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_srl_epi64(__m128i a, __m128i count) { return __builtin_ia32_psrlq128(a, count); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_epi8(__m128i a, __m128i b) { return (__m128i)((__v16qi)a == (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_epi16(__m128i a, __m128i b) { return (__m128i)((__v8hi)a == (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_epi32(__m128i a, __m128i b) { return (__m128i)((__v4si)a == (__v4si)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_epi8(__m128i a, __m128i b) { return (__m128i)((__v16qi)a > (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_epi16(__m128i a, __m128i b) { return (__m128i)((__v8hi)a > (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_epi32(__m128i a, __m128i b) { return (__m128i)((__v4si)a > (__v4si)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmplt_epi8(__m128i a, __m128i b) { return _mm_cmpgt_epi8(b,a); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmplt_epi16(__m128i a, __m128i b) { return _mm_cmpgt_epi16(b,a); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmplt_epi32(__m128i a, __m128i b) { return _mm_cmpgt_epi32(b,a); } #ifdef __x86_64__ -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi64_sd(__m128d a, long long b) { a[0] = b; return a; } -static inline long long __attribute__((__always_inline__, __nodebug__)) +static __inline__ long long __attribute__((__always_inline__, __nodebug__)) _mm_cvtsd_si64(__m128d a) { return __builtin_ia32_cvtsd2si64(a); } -static inline long long __attribute__((__always_inline__, __nodebug__)) +static __inline__ long long __attribute__((__always_inline__, __nodebug__)) _mm_cvttsd_si64(__m128d a) { return a[0]; } #endif -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtepi32_ps(__m128i a) { return __builtin_ia32_cvtdq2ps((__v4si)a); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtps_epi32(__m128 a) { return (__m128i)__builtin_ia32_cvtps2dq(a); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvttps_epi32(__m128 a) { return (__m128i)__builtin_ia32_cvttps2dq(a); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi32_si128(int a) { return (__m128i)(__v4si){ a, 0, 0, 0 }; } #ifdef __x86_64__ -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi64_si128(long long a) { return (__m128i){ a, 0 }; } #endif -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi128_si32(__m128i a) { __v4si b = (__v4si)a; @@ -997,207 +997,207 @@ _mm_cvtsi128_si32(__m128i a) } #ifdef __x86_64__ -static inline long long __attribute__((__always_inline__, __nodebug__)) +static __inline__ long long __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi128_si64(__m128i a) { return a[0]; } #endif -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_load_si128(__m128i const *p) { return *p; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_loadu_si128(__m128i const *p) { return (__m128i)__builtin_ia32_loaddqu((char const *)p); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_loadl_epi64(__m128i const *p) { return (__m128i) { *(long long*)p, 0}; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set_epi64x(long long q1, long long q0) { return (__m128i){ q0, q1 }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set_epi64(__m64 q1, __m64 q0) { return (__m128i){ (long long)q0, (long long)q1 }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set_epi32(int i3, int i2, int i1, int i0) { return (__m128i)(__v4si){ i0, i1, i2, i3}; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set_epi16(short w7, short w6, short w5, short w4, short w3, short w2, short w1, short w0) { return (__m128i)(__v8hi){ w0, w1, w2, w3, w4, w5, w6, w7 }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set_epi8(char b15, char b14, char b13, char b12, char b11, char b10, char b9, char b8, char b7, char b6, char b5, char b4, char b3, char b2, char b1, char b0) { return (__m128i)(__v16qi){ b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set1_epi64x(long long q) { return (__m128i){ q, q }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set1_epi64(__m64 q) { return (__m128i){ (long long)q, (long long)q }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set1_epi32(int i) { return (__m128i)(__v4si){ i, i, i, i }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set1_epi16(short w) { return (__m128i)(__v8hi){ w, w, w, w, w, w, w, w }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set1_epi8(char b) { return (__m128i)(__v16qi){ b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_setr_epi64(__m64 q0, __m64 q1) { return (__m128i){ (long long)q0, (long long)q1 }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_setr_epi32(int i0, int i1, int i2, int i3) { return (__m128i)(__v4si){ i0, i1, i2, i3}; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_setr_epi16(short w0, short w1, short w2, short w3, short w4, short w5, short w6, short w7) { return (__m128i)(__v8hi){ w0, w1, w2, w3, w4, w5, w6, w7 }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_setr_epi8(char b0, char b1, char b2, char b3, char b4, char b5, char b6, char b7, char b8, char b9, char b10, char b11, char b12, char b13, char b14, char b15) { return (__m128i)(__v16qi){ b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_setzero_si128(void) { return (__m128i){ 0LL, 0LL }; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_store_si128(__m128i *p, __m128i b) { *p = b; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storeu_si128(__m128i *p, __m128i b) { __builtin_ia32_storedqu((char *)p, (__v16qi)b); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_maskmoveu_si128(__m128i d, __m128i n, char *p) { __builtin_ia32_maskmovdqu((__v16qi)d, (__v16qi)n, p); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storel_epi64(__m128i *p, __m128i a) { __builtin_ia32_storelv4si((__v2si *)p, a); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_stream_pd(double *p, __m128d a) { __builtin_ia32_movntpd(p, a); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_stream_si128(__m128i *p, __m128i a) { __builtin_ia32_movntdq(p, a); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_stream_si32(int *p, int a) { __builtin_ia32_movnti(p, a); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_clflush(void const *p) { __builtin_ia32_clflush(p); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_lfence(void) { __builtin_ia32_lfence(); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_mfence(void) { __builtin_ia32_mfence(); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_packs_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_packsswb128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_packs_epi32(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_packssdw128((__v4si)a, (__v4si)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_packus_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_packuswb128((__v8hi)a, (__v8hi)b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_extract_epi16(__m128i a, int imm) { __v8hi b = (__v8hi)a; return b[imm]; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_insert_epi16(__m128i a, int b, int imm) { __v8hi c = (__v8hi)a; @@ -1205,7 +1205,7 @@ _mm_insert_epi16(__m128i a, int b, int imm) return (__m128i)c; } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_movemask_epi8(__m128i a) { return __builtin_ia32_pmovmskb128((__v16qi)a); @@ -1226,85 +1226,85 @@ _mm_movemask_epi8(__m128i a) 4 + ((imm) & 0x30) >> 4, \ 4 + ((imm) & 0xc0) >> 6)) -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_epi8(__m128i a, __m128i b) { return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_epi32(__m128i a, __m128i b) { return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 2, 4+2, 3, 4+3); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_epi64(__m128i a, __m128i b) { return (__m128i)__builtin_shufflevector(a, b, 1, 2+1); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_unpacklo_epi8(__m128i a, __m128i b) { return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_unpacklo_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_unpacklo_epi32(__m128i a, __m128i b) { return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 0, 4+0, 1, 4+1); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_unpacklo_epi64(__m128i a, __m128i b) { return (__m128i)__builtin_shufflevector(a, b, 0, 2+0); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_movepi64_pi64(__m128i a) { return (__m64)a[0]; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_movpi64_pi64(__m64 a) { return (__m128i){ (long long)a, 0 }; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_move_epi64(__m128i a) { return __builtin_shufflevector(a, (__m128i){ 0 }, 0, 2); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_pd(__m128d a, __m128d b) { return __builtin_shufflevector(a, b, 1, 2+1); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_unpacklo_pd(__m128d a, __m128d b) { return __builtin_shufflevector(a, b, 0, 2+0); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_movemask_pd(__m128d a) { return __builtin_ia32_movmskpd(a); @@ -1313,43 +1313,43 @@ _mm_movemask_pd(__m128d a) #define _mm_shuffle_pd(a, b, i) (__builtin_shufflevector((a), (b), (i) & 1, \ (((i) & 2) >> 1) + 2)) -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_castpd_ps(__m128d in) { return (__m128)in; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_castpd_si128(__m128d in) { return (__m128i)in; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_castps_pd(__m128 in) { return (__m128d)in; } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_castps_si128(__m128 in) { return (__m128i)in; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_castsi128_ps(__m128i in) { return (__m128)in; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_castsi128_pd(__m128i in) { return (__m128d)in; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_pause(void) { __asm__ volatile ("pause"); diff --git a/lib/Headers/mm_malloc.h b/lib/Headers/mm_malloc.h index a680c47..fba8651 100644 --- a/lib/Headers/mm_malloc.h +++ b/lib/Headers/mm_malloc.h @@ -27,7 +27,8 @@ #include <errno.h> #include <stdlib.h> -static inline void *__attribute__((__always_inline__, __nodebug__)) _mm_malloc(size_t size, size_t align) +static __inline__ void *__attribute__((__always_inline__, __nodebug__)) +_mm_malloc(size_t size, size_t align) { if (align & (align - 1)) { errno = EINVAL; @@ -44,13 +45,15 @@ static inline void *__attribute__((__always_inline__, __nodebug__)) _mm_malloc(s if (!mallocedMemory) return 0; - void *alignedMemory = (void *)(((size_t)mallocedMemory + align) & ~((size_t)align - 1)); + void *alignedMemory = + (void *)(((size_t)mallocedMemory + align) & ~((size_t)align - 1)); ((void **)alignedMemory)[-1] = mallocedMemory; return alignedMemory; } -static inline void __attribute__((__always_inline__, __nodebug__)) _mm_free(void *p) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) +_mm_free(void *p) { if (p) free(((void **)p)[-1]); diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h index 0f06f78..401d8a7 100644 --- a/lib/Headers/mmintrin.h +++ b/lib/Headers/mmintrin.h @@ -34,409 +34,409 @@ typedef int __v2si __attribute__((__vector_size__(8))); typedef short __v4hi __attribute__((__vector_size__(8))); typedef char __v8qi __attribute__((__vector_size__(8))); -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_empty(void) { __builtin_ia32_emms(); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi32_si64(int __i) { return (__m64)(__v2si){__i, 0}; } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi64_si32(__m64 __m) { __v2si __mmx_var2 = (__v2si)__m; return __mmx_var2[0]; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi64_m64(long long __i) { return (__m64)__i; } -static inline long long __attribute__((__always_inline__, __nodebug__)) +static __inline__ long long __attribute__((__always_inline__, __nodebug__)) _mm_cvtm64_si64(__m64 __m) { return (long long)__m; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_packs_pi16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_packsswb((__v4hi)__m1, (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_packs_pi32(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_packssdw((__v2si)__m1, (__v2si)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_packs_pu16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_packuswb((__v4hi)__m1, (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_pi8(__m64 __m1, __m64 __m2) { return (__m64)__builtin_shufflevector((__v8qi)__m1, (__v8qi)__m2, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_pi16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_shufflevector((__v4hi)__m1, (__v4hi)__m2, 2, 4+2, 3, 4+3); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_pi32(__m64 __m1, __m64 __m2) { return (__m64)__builtin_shufflevector((__v2si)__m1, (__v2si)__m2, 1, 2+1); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_unpacklo_pi8(__m64 __m1, __m64 __m2) { return (__m64)__builtin_shufflevector((__v8qi)__m1, (__v8qi)__m2, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_unpacklo_pi16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_shufflevector((__v4hi)__m1, (__v4hi)__m2, 0, 4+0, 1, 4+1); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_unpacklo_pi32(__m64 __m1, __m64 __m2) { return (__m64)__builtin_shufflevector((__v2si)__m1, (__v2si)__m2, 0, 2+0); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_add_pi8(__m64 __m1, __m64 __m2) { return (__m64)((__v8qi)__m1 + (__v8qi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_add_pi16(__m64 __m1, __m64 __m2) { return (__m64)((__v4hi)__m1 + (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_add_pi32(__m64 __m1, __m64 __m2) { return (__m64)((__v2si)__m1 + (__v2si)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_adds_pi8(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_paddsb((__v8qi)__m1, (__v8qi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_adds_pi16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_paddsw((__v4hi)__m1, (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_adds_pu8(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_paddusb((__v8qi)__m1, (__v8qi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_adds_pu16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_paddusw((__v4hi)__m1, (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sub_pi8(__m64 __m1, __m64 __m2) { return (__m64)((__v8qi)__m1 - (__v8qi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sub_pi16(__m64 __m1, __m64 __m2) { return (__m64)((__v4hi)__m1 - (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sub_pi32(__m64 __m1, __m64 __m2) { return (__m64)((__v2si)__m1 - (__v2si)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_subs_pi8(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_psubsb((__v8qi)__m1, (__v8qi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_subs_pi16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_psubsw((__v4hi)__m1, (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_subs_pu8(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_psubusb((__v8qi)__m1, (__v8qi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_subs_pu16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_psubusw((__v4hi)__m1, (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_madd_pi16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_pmaddwd((__v4hi)__m1, (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_mulhi_pi16(__m64 __m1, __m64 __m2) { return (__m64)__builtin_ia32_pmulhw((__v4hi)__m1, (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_mullo_pi16(__m64 __m1, __m64 __m2) { return (__m64)((__v4hi)__m1 * (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sll_pi16(__m64 __m, __m64 __count) { return (__m64)__builtin_ia32_psllw((__v4hi)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_slli_pi16(__m64 __m, int __count) { return (__m64)__builtin_ia32_psllwi((__v4hi)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sll_pi32(__m64 __m, __m64 __count) { return (__m64)__builtin_ia32_pslld((__v2si)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_slli_pi32(__m64 __m, int __count) { return (__m64)__builtin_ia32_pslldi((__v2si)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sll_si64(__m64 __m, __m64 __count) { return __builtin_ia32_psllq(__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_slli_si64(__m64 __m, int __count) { return __builtin_ia32_psllqi(__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sra_pi16(__m64 __m, __m64 __count) { return (__m64)__builtin_ia32_psraw((__v4hi)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_srai_pi16(__m64 __m, int __count) { return (__m64)__builtin_ia32_psrawi((__v4hi)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sra_pi32(__m64 __m, __m64 __count) { return (__m64)__builtin_ia32_psrad((__v2si)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_srai_pi32(__m64 __m, int __count) { return (__m64)__builtin_ia32_psradi((__v2si)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_srl_pi16(__m64 __m, __m64 __count) { return (__m64)__builtin_ia32_psrlw((__v4hi)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_srli_pi16(__m64 __m, int __count) { return (__m64)__builtin_ia32_psrlwi((__v4hi)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_srl_pi32(__m64 __m, __m64 __count) { return (__m64)__builtin_ia32_psrld((__v2si)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_srli_pi32(__m64 __m, int __count) { return (__m64)__builtin_ia32_psrldi((__v2si)__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_srl_si64(__m64 __m, __m64 __count) { return (__m64)__builtin_ia32_psrlq(__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_srli_si64(__m64 __m, int __count) { return __builtin_ia32_psrlqi(__m, __count); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_and_si64(__m64 __m1, __m64 __m2) { return __m1 & __m2; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_andnot_si64(__m64 __m1, __m64 __m2) { return ~__m1 & __m2; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_or_si64(__m64 __m1, __m64 __m2) { return __m1 | __m2; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_xor_si64(__m64 __m1, __m64 __m2) { return __m1 ^ __m2; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_pi8(__m64 __m1, __m64 __m2) { return (__m64)((__v8qi)__m1 == (__v8qi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_pi16(__m64 __m1, __m64 __m2) { return (__m64)((__v4hi)__m1 == (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_pi32(__m64 __m1, __m64 __m2) { return (__m64)((__v2si)__m1 == (__v2si)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_pi8(__m64 __m1, __m64 __m2) { return (__m64)((__v8qi)__m1 > (__v8qi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_pi16(__m64 __m1, __m64 __m2) { return (__m64)((__v4hi)__m1 > (__v4hi)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_pi32(__m64 __m1, __m64 __m2) { return (__m64)((__v2si)__m1 > (__v2si)__m2); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_setzero_si64(void) { return (__m64){ 0LL }; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_set_pi32(int __i1, int __i0) { return (__m64)(__v2si){ __i0, __i1 }; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_set_pi16(short __s3, short __s2, short __s1, short __s0) { return (__m64)(__v4hi){ __s0, __s1, __s2, __s3 }; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_set_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2, char __b1, char __b0) { return (__m64)(__v8qi){ __b0, __b1, __b2, __b3, __b4, __b5, __b6, __b7 }; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_set1_pi32(int __i) { return (__m64)(__v2si){ __i, __i }; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_set1_pi16(short __s) { return (__m64)(__v4hi){ __s, __s, __s, __s }; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_set1_pi8(char __b) { return (__m64)(__v8qi){ __b, __b, __b, __b, __b, __b, __b, __b }; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_setr_pi32(int __i1, int __i0) { return (__m64)(__v2si){ __i1, __i0 }; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_setr_pi16(short __s3, short __s2, short __s1, short __s0) { return (__m64)(__v4hi){ __s3, __s2, __s1, __s0 }; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_setr_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2, char __b1, char __b0) { diff --git a/lib/Headers/pmmintrin.h b/lib/Headers/pmmintrin.h index cd90166..7ca386c 100644 --- a/lib/Headers/pmmintrin.h +++ b/lib/Headers/pmmintrin.h @@ -30,67 +30,67 @@ #include <emmintrin.h> -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_lddqu_si128(__m128i const *p) { return (__m128i)__builtin_ia32_lddqu((char const *)p); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_addsub_ps(__m128 a, __m128 b) { return __builtin_ia32_addsubps(a, b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_hadd_ps(__m128 a, __m128 b) { return __builtin_ia32_haddps(a, b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_hsub_ps(__m128 a, __m128 b) { return __builtin_ia32_hsubps(a, b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_movehdup_ps(__m128 a) { return __builtin_shufflevector(a, a, 1, 1, 3, 3); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_moveldup_ps(__m128 a) { return __builtin_shufflevector(a, a, 0, 0, 2, 2); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_addsub_pd(__m128d a, __m128d b) { return __builtin_ia32_addsubpd(a, b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_hadd_pd(__m128d a, __m128d b) { return __builtin_ia32_haddpd(a, b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_hsub_pd(__m128d a, __m128d b) { return __builtin_ia32_hsubpd(a, b); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loaddup_pd(double const *dp) { return (__m128d){ *dp, *dp }; } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_movedup_pd(__m128d a) { return __builtin_shufflevector(a, a, 0, 0); @@ -104,13 +104,13 @@ _mm_movedup_pd(__m128d a) #define _MM_GET_DENORMALS_ZERO_MODE() (_mm_getcsr() & _MM_DENORMALS_ZERO_MASK) #define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x))) -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_monitor(void const *p, unsigned extensions, unsigned hints) { __builtin_ia32_monitor((void *)p, extensions, hints); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_mwait(unsigned extensions, unsigned hints) { __builtin_ia32_mwait(extensions, hints); diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h index 9c8d53d..e271f99 100644 --- a/lib/Headers/smmintrin.h +++ b/lib/Headers/smmintrin.h @@ -1,25 +1,25 @@ -/*===---- smmintrin.h - SSE 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. -* -*===-----------------------------------------------------------------------=== -*/ +/*===---- smmintrin.h - SSE4 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 _SMMINTRIN_H #define _SMMINTRIN_H @@ -67,53 +67,53 @@ typedef long long __v2di __attribute__ ((__vector_size__ (16))); #define _mm_round_sd(X, Y, M) __builtin_ia32_roundsd((X), (Y), (M)) /* SSE4 Packed Blending Intrinsics. */ -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_blend_pd (__m128d __V1, __m128d __V2, const int __M) { return (__m128d) __builtin_ia32_blendpd ((__v2df)__V1, (__v2df)__V2, __M); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_blend_ps (__m128 __V1, __m128 __V2, const int __M) { return (__m128) __builtin_ia32_blendps ((__v4sf)__V1, (__v4sf)__V2, __M); } -static inline __m128d __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_blendv_pd (__m128d __V1, __m128d __V2, __m128d __M) { return (__m128d) __builtin_ia32_blendvpd ((__v2df)__V1, (__v2df)__V2, (__v2df)__M); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_blendv_ps (__m128 __V1, __m128 __V2, __m128 __M) { return (__m128) __builtin_ia32_blendvps ((__v4sf)__V1, (__v4sf)__V2, (__v4sf)__M); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M) { return (__m128i) __builtin_ia32_pblendvb128 ((__v16qi)__V1, (__v16qi)__V2, (__v16qi)__M); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_blend_epi16 (__m128i __V1, __m128i __V2, const int __M) { return (__m128i) __builtin_ia32_pblendw128 ((__v8hi)__V1, (__v8hi)__V2, __M); } /* SSE4 Dword Multiply Instructions. */ -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_mullo_epi32 (__m128i __V1, __m128i __V2) { - return (__m128i) __builtin_ia32_pmulld128((__v4si)__V1, (__v4si)__V2); + return (__m128i) ((__v4si)__V1 * (__v4si)__V2); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_mul_epi32 (__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pmuldq128 ((__v4si)__V1, (__v4si)__V2); @@ -124,56 +124,56 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2) #define _mm_dp_pd(X, Y, M) __builtin_ia32_dppd ((X), (Y), (M)) /* SSE4 Streaming Load Hint Instruction. */ -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_stream_load_si128 (__m128i *__V) { return (__m128i) __builtin_ia32_movntdqa ((__v2di *) __V); } /* SSE4 Packed Integer Min/Max Instructions. */ -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_min_epi8 (__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pminsb128 ((__v16qi) __V1, (__v16qi) __V2); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_max_epi8 (__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pmaxsb128 ((__v16qi) __V1, (__v16qi) __V2); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_min_epu16 (__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pminuw128 ((__v8hi) __V1, (__v8hi) __V2); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_max_epu16 (__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pmaxuw128 ((__v8hi) __V1, (__v8hi) __V2); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_min_epi32 (__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pminsd128 ((__v4si) __V1, (__v4si) __V2); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_max_epi32 (__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pmaxsd128 ((__v4si) __V1, (__v4si) __V2); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_min_epu32 (__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pminud128((__v4si) __V1, (__v4si) __V2); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_max_epu32 (__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pmaxud128((__v4si) __V1, (__v4si) __V2); @@ -224,19 +224,19 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) #endif /* __x86_64 */ /* SSE4 128-bit Packed Integer Comparisons. */ -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_testz_si128(__m128i __M, __m128i __V) { return __builtin_ia32_ptestz128((__v2di)__M, (__v2di)__V); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_testc_si128(__m128i __M, __m128i __V) { return __builtin_ia32_ptestc128((__v2di)__M, (__v2di)__V); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_testnzc_si128(__m128i __M, __m128i __V) { return __builtin_ia32_ptestnzc128((__v2di)__M, (__v2di)__V); @@ -247,88 +247,88 @@ _mm_testnzc_si128(__m128i __M, __m128i __V) #define _mm_test_all_zeros(M, V) _mm_testz_si128 ((V), (V)) /* SSE4 64-bit Packed Integer Comparisons. */ -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_epi64(__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_pcmpeqq((__v2di)__V1, (__v2di)__V2); } /* SSE4 Packed Integer Sign-Extension. */ -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepi8_epi16(__m128i __V) { return (__m128i) __builtin_ia32_pmovsxbw128((__v16qi) __V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepi8_epi32(__m128i __V) { return (__m128i) __builtin_ia32_pmovsxbd128((__v16qi) __V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepi8_epi64(__m128i __V) { return (__m128i) __builtin_ia32_pmovsxbq128((__v16qi) __V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepi16_epi32(__m128i __V) { return (__m128i) __builtin_ia32_pmovsxwd128((__v8hi) __V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepi16_epi64(__m128i __V) { return (__m128i) __builtin_ia32_pmovsxwq128((__v8hi)__V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepi32_epi64(__m128i __V) { return (__m128i) __builtin_ia32_pmovsxdq128((__v4si)__V); } /* SSE4 Packed Integer Zero-Extension. */ -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepu8_epi16(__m128i __V) { return (__m128i) __builtin_ia32_pmovzxbw128((__v16qi) __V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepu8_epi32(__m128i __V) { return (__m128i) __builtin_ia32_pmovzxbd128((__v16qi)__V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepu8_epi64(__m128i __V) { return (__m128i) __builtin_ia32_pmovzxbq128((__v16qi)__V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepu16_epi32(__m128i __V) { return (__m128i) __builtin_ia32_pmovzxwd128((__v8hi)__V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepu16_epi64(__m128i __V) { return (__m128i) __builtin_ia32_pmovzxwq128((__v8hi)__V); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cvtepu32_epi64(__m128i __V) { return (__m128i) __builtin_ia32_pmovzxdq128((__v4si)__V); } /* SSE4 Pack with Unsigned Saturation. */ -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_packus_epi32(__m128i __V1, __m128i __V2) { return (__m128i) __builtin_ia32_packusdw128((__v4si)__V1, (__v4si)__V2); @@ -400,33 +400,33 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2) __builtin_ia32_pcmpestriz128((A), (LA), (B), (LB), (M)) /* SSE4.2 Compare Packed Data -- Greater Than. */ -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_epi64(__m128i __V1, __m128i __V2) { return __builtin_ia32_pcmpgtq((__v2di)__V1, (__v2di)__V2); } /* SSE4.2 Accumulate CRC32. */ -static inline unsigned int __attribute__((__always_inline__, __nodebug__)) +static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__)) _mm_crc32_u8(unsigned int __C, unsigned char __D) { return __builtin_ia32_crc32qi(__C, __D); } -static inline unsigned int __attribute__((__always_inline__, __nodebug__)) +static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__)) _mm_crc32_u16(unsigned int __C, unsigned short __D) { return __builtin_ia32_crc32hi(__C, __D); } -static inline unsigned int __attribute__((__always_inline__, __nodebug__)) +static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__)) _mm_crc32_u32(unsigned int __C, unsigned int __D) { return __builtin_ia32_crc32si(__C, __D); } #ifdef __x86_64__ -static inline unsigned long long __attribute__((__always_inline__, __nodebug__)) +static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__)) _mm_crc32_u64(unsigned long long __C, unsigned long long __D) { return __builtin_ia32_crc32di(__C, __D); @@ -434,14 +434,14 @@ _mm_crc32_u64(unsigned long long __C, unsigned long long __D) #endif /* __x86_64__ */ /* SSE4.2 Population Count. */ -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_popcnt_u32(unsigned int __A) { return __builtin_popcount(__A); } #ifdef __x86_64__ -static inline long long __attribute__((__always_inline__, __nodebug__)) +static __inline__ long long __attribute__((__always_inline__, __nodebug__)) _mm_popcnt_u64(unsigned long long __A) { return __builtin_popcountll(__A); diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h index 7adb776..09ebc23 100644 --- a/lib/Headers/tmmintrin.h +++ b/lib/Headers/tmmintrin.h @@ -30,37 +30,37 @@ #include <pmmintrin.h> -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_abs_pi8(__m64 a) { return (__m64)__builtin_ia32_pabsb((__v8qi)a); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_abs_epi8(__m128i a) { return (__m128i)__builtin_ia32_pabsb128((__v16qi)a); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_abs_pi16(__m64 a) { return (__m64)__builtin_ia32_pabsw((__v4hi)a); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_abs_epi16(__m128i a) { return (__m128i)__builtin_ia32_pabsw128((__v8hi)a); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_abs_pi32(__m64 a) { return (__m64)__builtin_ia32_pabsd((__v2si)a); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_abs_epi32(__m128i a) { return (__m128i)__builtin_ia32_pabsd128((__v4si)a); @@ -69,145 +69,145 @@ _mm_abs_epi32(__m128i a) #define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n))) #define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8))) -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hadd_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_phaddw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hadd_epi32(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_phaddd128((__v4si)a, (__v4si)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_hadd_pi16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_phaddw((__v4hi)a, (__v4hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_hadd_pi32(__m64 a, __m64 b) { return (__m64)__builtin_ia32_phaddd((__v2si)a, (__v2si)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hadds_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_phaddsw128((__v8hi)a, (__v8hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_hadds_pi16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_phaddsw((__v4hi)a, (__v4hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hsub_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_phsubw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hsub_epi32(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_phsubd128((__v4si)a, (__v4si)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_hsub_pi16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_phsubw((__v4hi)a, (__v4hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_hsub_pi32(__m64 a, __m64 b) { return (__m64)__builtin_ia32_phsubd((__v2si)a, (__v2si)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hsubs_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_phsubsw128((__v8hi)a, (__v8hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_hsubs_pi16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_phsubsw((__v4hi)a, (__v4hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_maddubs_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pmaddubsw128((__v16qi)a, (__v16qi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_maddubs_pi16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pmaddubsw((__v8qi)a, (__v8qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_mulhrs_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pmulhrsw128((__v8hi)a, (__v8hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_mulhrs_pi16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pmulhrsw((__v4hi)a, (__v4hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_shuffle_epi8(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_pshufb128((__v16qi)a, (__v16qi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_shuffle_pi8(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pshufb((__v8qi)a, (__v8qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sign_epi8(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_psignb128((__v16qi)a, (__v16qi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sign_epi16(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_psignw128((__v8hi)a, (__v8hi)b); } -static inline __m128i __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_sign_epi32(__m128i a, __m128i b) { return (__m128i)__builtin_ia32_psignd128((__v4si)a, (__v4si)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sign_pi8(__m64 a, __m64 b) { return (__m64)__builtin_ia32_psignb((__v8qi)a, (__v8qi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sign_pi16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_psignw((__v4hi)a, (__v4hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sign_pi32(__m64 a, __m64 b) { return (__m64)__builtin_ia32_psignd((__v2si)a, (__v2si)b); diff --git a/lib/Headers/wmmintrin.h b/lib/Headers/wmmintrin.h new file mode 100644 index 0000000..6b2e468 --- /dev/null +++ b/lib/Headers/wmmintrin.h @@ -0,0 +1,67 @@ +/*===---- wmmintrin.h - AES 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 _WMMINTRIN_H +#define _WMMINTRIN_H + +#if !defined (__AES__) +# error "AES instructions not enabled" +#else + +#include <smmintrin.h> + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesenc_si128(__m128i __V, __m128i __R) +{ + return (__m128i)__builtin_ia32_aesenc128(__V, __R); +} + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesenclast_si128(__m128i __V, __m128i __R) +{ + return (__m128i)__builtin_ia32_aesenclast128(__V, __R); +} + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesdec_si128(__m128i __V, __m128i __R) +{ + return (__m128i)__builtin_ia32_aesdec128(__V, __R); +} + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesdeclast_si128(__m128i __V, __m128i __R) +{ + return (__m128i)__builtin_ia32_aesdeclast128(__V, __R); +} + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesimc_si128(__m128i __V) +{ + return (__m128i)__builtin_ia32_aesimc128(__V); +} + +#define _mm_aeskeygenassist_si128(C, R) \ + __builtin_ia32_aeskeygenassist128((C), (R)) + +#endif /* __AES__ */ +#endif /* _WMMINTRIN_H */ diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index 06e616b..4e313b2 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -36,365 +36,365 @@ typedef float __m128 __attribute__((__vector_size__(16))); #include <mm_malloc.h> -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_add_ss(__m128 a, __m128 b) { a[0] += b[0]; return a; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_add_ps(__m128 a, __m128 b) { return a + b; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_sub_ss(__m128 a, __m128 b) { a[0] -= b[0]; return a; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_sub_ps(__m128 a, __m128 b) { return a - b; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_mul_ss(__m128 a, __m128 b) { a[0] *= b[0]; return a; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_mul_ps(__m128 a, __m128 b) { return a * b; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_div_ss(__m128 a, __m128 b) { a[0] /= b[0]; return a; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_div_ps(__m128 a, __m128 b) { return a / b; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_sqrt_ss(__m128 a) { return __builtin_ia32_sqrtss(a); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_sqrt_ps(__m128 a) { return __builtin_ia32_sqrtps(a); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_rcp_ss(__m128 a) { return __builtin_ia32_rcpss(a); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_rcp_ps(__m128 a) { return __builtin_ia32_rcpps(a); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_rsqrt_ss(__m128 a) { return __builtin_ia32_rsqrtss(a); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_rsqrt_ps(__m128 a) { return __builtin_ia32_rsqrtps(a); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_min_ss(__m128 a, __m128 b) { return __builtin_ia32_minss(a, b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_min_ps(__m128 a, __m128 b) { return __builtin_ia32_minps(a, b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_max_ss(__m128 a, __m128 b) { return __builtin_ia32_maxss(a, b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_max_ps(__m128 a, __m128 b) { return __builtin_ia32_maxps(a, b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_and_ps(__m128 a, __m128 b) { return (__m128)((__v4si)a & (__v4si)b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_andnot_ps(__m128 a, __m128 b) { return (__m128)(~(__v4si)a & (__v4si)b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_or_ps(__m128 a, __m128 b) { return (__m128)((__v4si)a | (__v4si)b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_xor_ps(__m128 a, __m128 b) { return (__m128)((__v4si)a ^ (__v4si)b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(a, b, 0); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpeq_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(a, b, 0); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmplt_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(a, b, 1); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmplt_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(a, b, 1); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmple_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(a, b, 2); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmple_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(a, b, 2); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(b, a, 1); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpgt_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(b, a, 1); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpge_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(b, a, 2); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpge_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(b, a, 2); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpneq_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(a, b, 4); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpneq_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(a, b, 4); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpnlt_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(a, b, 5); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpnlt_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(a, b, 5); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpnle_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(a, b, 6); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpnle_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(a, b, 6); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpngt_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(b, a, 5); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpngt_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(b, a, 5); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpnge_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(b, a, 6); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpnge_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(b, a, 6); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpord_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(a, b, 7); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpord_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(a, b, 7); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpunord_ss(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpss(a, b, 3); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cmpunord_ps(__m128 a, __m128 b) { return (__m128)__builtin_ia32_cmpps(a, b, 3); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comieq_ss(__m128 a, __m128 b) { return __builtin_ia32_comieq(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comilt_ss(__m128 a, __m128 b) { return __builtin_ia32_comilt(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comile_ss(__m128 a, __m128 b) { return __builtin_ia32_comile(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comigt_ss(__m128 a, __m128 b) { return __builtin_ia32_comigt(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comige_ss(__m128 a, __m128 b) { return __builtin_ia32_comige(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comineq_ss(__m128 a, __m128 b) { return __builtin_ia32_comineq(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomieq_ss(__m128 a, __m128 b) { return __builtin_ia32_ucomieq(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomilt_ss(__m128 a, __m128 b) { return __builtin_ia32_ucomilt(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomile_ss(__m128 a, __m128 b) { return __builtin_ia32_ucomile(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomigt_ss(__m128 a, __m128 b) { return __builtin_ia32_ucomigt(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomige_ss(__m128 a, __m128 b) { return __builtin_ia32_ucomige(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomineq_ss(__m128 a, __m128 b) { return __builtin_ia32_ucomineq(a, b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_cvtss_si32(__m128 a) { return __builtin_ia32_cvtss2si(a); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_cvt_ss2si(__m128 a) { return _mm_cvtss_si32(a); @@ -402,7 +402,7 @@ _mm_cvt_ss2si(__m128 a) #ifdef __x86_64__ -static inline long long __attribute__((__always_inline__, __nodebug__)) +static __inline__ long long __attribute__((__always_inline__, __nodebug__)) _mm_cvtss_si64(__m128 a) { return __builtin_ia32_cvtss2si64(a); @@ -410,37 +410,37 @@ _mm_cvtss_si64(__m128 a) #endif -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cvtps_pi32(__m128 a) { return (__m64)__builtin_ia32_cvtps2pi(a); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_cvttss_si32(__m128 a) { return a[0]; } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_cvtt_ss2si(__m128 a) { return _mm_cvttss_si32(a); } -static inline long long __attribute__((__always_inline__, __nodebug__)) +static __inline__ long long __attribute__((__always_inline__, __nodebug__)) _mm_cvttss_si64(__m128 a) { return a[0]; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cvttps_pi32(__m128 a) { return (__m64)__builtin_ia32_cvttps2pi(a); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi32_ss(__m128 a, int b) { a[0] = b; @@ -449,7 +449,7 @@ _mm_cvtsi32_ss(__m128 a, int b) #ifdef __x86_64__ -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi64_ss(__m128 a, long long b) { a[0] = b; @@ -458,19 +458,19 @@ _mm_cvtsi64_ss(__m128 a, long long b) #endif -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtpi32_ps(__m128 a, __m64 b) { return __builtin_ia32_cvtpi2ps(a, (__v2si)b); } -static inline float __attribute__((__always_inline__, __nodebug__)) +static __inline__ float __attribute__((__always_inline__, __nodebug__)) _mm_cvtss_f32(__m128 a) { return a[0]; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_loadh_pi(__m128 a, const __m64 *p) { __m128 b; @@ -479,7 +479,7 @@ _mm_loadh_pi(__m128 a, const __m64 *p) return __builtin_shufflevector(a, b, 0, 1, 4, 5); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_loadl_pi(__m128 a, const __m64 *p) { __m128 b; @@ -488,13 +488,13 @@ _mm_loadl_pi(__m128 a, const __m64 *p) return __builtin_shufflevector(a, b, 4, 5, 2, 3); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_load_ss(const float *p) { return (__m128){ *p, 0, 0, 0 }; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_load1_ps(const float *p) { return (__m128){ *p, *p, *p, *p }; @@ -502,100 +502,100 @@ _mm_load1_ps(const float *p) #define _mm_load_ps1(p) _mm_load1_ps(p) -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_load_ps(const float *p) { return *(__m128*)p; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_loadu_ps(const float *p) { return __builtin_ia32_loadups(p); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_loadr_ps(const float *p) { __m128 a = _mm_load_ps(p); return __builtin_shufflevector(a, a, 3, 2, 1, 0); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_set_ss(float w) { return (__m128){ w, 0, 0, 0 }; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_set1_ps(float w) { return (__m128){ w, w, w, w }; } // Microsoft specific. -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_set_ps1(float w) { return _mm_set1_ps(w); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_set_ps(float z, float y, float x, float w) { return (__m128){ w, x, y, z }; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_setr_ps(float z, float y, float x, float w) { return (__m128){ z, y, x, w }; } -static inline __m128 __attribute__((__always_inline__)) +static __inline__ __m128 __attribute__((__always_inline__)) _mm_setzero_ps(void) { return (__m128){ 0, 0, 0, 0 }; } -static inline void __attribute__((__always_inline__)) +static __inline__ void __attribute__((__always_inline__)) _mm_storeh_pi(__m64 *p, __m128 a) { __builtin_ia32_storehps((__v2si *)p, a); } -static inline void __attribute__((__always_inline__)) +static __inline__ void __attribute__((__always_inline__)) _mm_storel_pi(__m64 *p, __m128 a) { __builtin_ia32_storelps((__v2si *)p, a); } -static inline void __attribute__((__always_inline__)) +static __inline__ void __attribute__((__always_inline__)) _mm_store_ss(float *p, __m128 a) { *p = a[0]; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storeu_ps(float *p, __m128 a) { __builtin_ia32_storeups(p, a); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_store1_ps(float *p, __m128 a) { a = __builtin_shufflevector(a, a, 0, 0, 0, 0); _mm_storeu_ps(p, a); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_store_ps(float *p, __m128 a) { *(__m128 *)p = a; } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storer_ps(float *p, __m128 a) { a = __builtin_shufflevector(a, a, 3, 2, 1, 0); @@ -612,32 +612,32 @@ _mm_storer_ps(float *p, __m128 a) #define _mm_prefetch(a, sel) (__builtin_prefetch((void *)a, 0, sel)) -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_stream_pi(__m64 *p, __m64 a) { __builtin_ia32_movntq(p, a); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_stream_ps(float *p, __m128 a) { __builtin_ia32_movntps(p, a); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_sfence(void) { __builtin_ia32_sfence(); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_extract_pi16(__m64 a, int n) { __v4hi b = (__v4hi)a; return (unsigned short)b[n & 3]; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_insert_pi16(__m64 a, int d, int n) { __v4hi b = (__v4hi)a; @@ -645,37 +645,37 @@ _mm_insert_pi16(__m64 a, int d, int n) return (__m64)b; } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_max_pi16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pmaxsw((__v4hi)a, (__v4hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_max_pu8(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pmaxub((__v8qi)a, (__v8qi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_min_pi16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pminsw((__v4hi)a, (__v4hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_min_pu8(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pminub((__v8qi)a, (__v8qi)b); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_movemask_pi8(__m64 a) { return __builtin_ia32_pmovmskb((__v8qi)a); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_mulhi_pu16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pmulhuw((__v4hi)a, (__v4hi)b); @@ -686,37 +686,37 @@ _mm_mulhi_pu16(__m64 a, __m64 b) (n) & 0x3, ((n) & 0xc) >> 2, \ ((n) & 0x30) >> 4, ((n) & 0xc0) >> 6)) -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_maskmove_si64(__m64 d, __m64 n, char *p) { __builtin_ia32_maskmovq((__v8qi)d, (__v8qi)n, p); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_avg_pu8(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pavgb((__v8qi)a, (__v8qi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_avg_pu16(__m64 a, __m64 b) { return (__m64)__builtin_ia32_pavgw((__v4hi)a, (__v4hi)b); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_sad_pu8(__m64 a, __m64 b) { return (__m64)__builtin_ia32_psadbw((__v8qi)a, (__v8qi)b); } -static inline unsigned int __attribute__((__always_inline__, __nodebug__)) +static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__)) _mm_getcsr(void) { return __builtin_ia32_stmxcsr(); } -static inline void __attribute__((__always_inline__, __nodebug__)) +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_setcsr(unsigned int i) { __builtin_ia32_ldmxcsr(i); @@ -727,37 +727,37 @@ _mm_setcsr(unsigned int i) (((mask) & 0x30) >> 4) + 4, \ (((mask) & 0xc0) >> 6) + 4)) -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_ps(__m128 a, __m128 b) { return __builtin_shufflevector(a, b, 2, 6, 3, 7); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_unpacklo_ps(__m128 a, __m128 b) { return __builtin_shufflevector(a, b, 0, 4, 1, 5); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_move_ss(__m128 a, __m128 b) { return __builtin_shufflevector(a, b, 4, 1, 2, 3); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_movehl_ps(__m128 a, __m128 b) { return __builtin_shufflevector(a, b, 6, 7, 2, 3); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_movelh_ps(__m128 a, __m128 b) { return __builtin_shufflevector(a, b, 0, 1, 4, 5); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtpi16_ps(__m64 a) { __m64 b, c; @@ -775,7 +775,7 @@ _mm_cvtpi16_ps(__m64 a) return r; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtpu16_ps(__m64 a) { __m64 b, c; @@ -792,7 +792,7 @@ _mm_cvtpu16_ps(__m64 a) return r; } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtpi8_ps(__m64 a) { __m64 b; @@ -804,7 +804,7 @@ _mm_cvtpi8_ps(__m64 a) return _mm_cvtpi16_ps(b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtpu8_ps(__m64 a) { __m64 b; @@ -815,7 +815,7 @@ _mm_cvtpu8_ps(__m64 a) return _mm_cvtpi16_ps(b); } -static inline __m128 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtpi32x2_ps(__m64 a, __m64 b) { __m128 c; @@ -827,7 +827,7 @@ _mm_cvtpi32x2_ps(__m64 a, __m64 b) return _mm_cvtpi32_ps(c, a); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cvtps_pi16(__m128 a) { __m64 b, c; @@ -839,7 +839,7 @@ _mm_cvtps_pi16(__m128 a) return _mm_packs_pi16(b, c); } -static inline __m64 __attribute__((__always_inline__, __nodebug__)) +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cvtps_pi8(__m128 a) { __m64 b, c; @@ -850,7 +850,7 @@ _mm_cvtps_pi8(__m128 a) return _mm_packs_pi16(b, c); } -static inline int __attribute__((__always_inline__, __nodebug__)) +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_movemask_ps(__m128 a) { return __builtin_ia32_movmskps(a); diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 2f89142..19f25ea 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -1372,8 +1372,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // a pedwarn. if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) Diag(BufferEnd, diag::ext_no_newline_eof) - << CodeModificationHint::CreateInsertion(getSourceLocation(BufferEnd), - "\n"); + << FixItHint::CreateInsertion(getSourceLocation(BufferEnd), "\n"); BufferPtr = CurPtr; diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 7b60101..757ba90 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -127,10 +127,10 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) { // Add a fixit in GNU/C99/C++ mode. Don't offer a fixit for strict-C89, // because it is more trouble than it is worth to insert /**/ and check that // there is no /**/ in the range also. - CodeModificationHint FixItHint; + FixItHint Hint; if (Features.GNUMode || Features.C99 || Features.CPlusPlus) - FixItHint = CodeModificationHint::CreateInsertion(Tmp.getLocation(),"//"); - Diag(Tmp, diag::ext_pp_extra_tokens_at_eol) << DirType << FixItHint; + Hint = FixItHint::CreateInsertion(Tmp.getLocation(),"//"); + Diag(Tmp, diag::ext_pp_extra_tokens_at_eol) << DirType << Hint; DiscardUntilEndOfDirective(); } } diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 6d1c132..335d3db 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -255,6 +255,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { if (!I->second->isUsed()) Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used); } + return true; } diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index ffae8ab..1c6a5ad 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -258,10 +258,13 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, InstantiationEnd,Identifier.getLength()); Identifier.setLocation(Loc); - // If this is #define X X, we must mark the result as unexpandible. - if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) - if (getMacroInfo(NewII) == MI) - Identifier.setFlag(Token::DisableExpand); + // If this is a disabled macro or #define X X, we must mark the result as + // unexpandable. + if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) { + if (MacroInfo *NewMI = getMacroInfo(NewII)) + if (!NewMI->isEnabled() || NewMI == MI) + Identifier.setFlag(Token::DisableExpand); + } // Since this is not an identifier token, it can't be macro expanded, so // we're done. diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 9d59300..8b4b1dd 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -519,6 +519,11 @@ bool Preprocessor::EnterMainSourceFile() { return EnterSourceFile(FID, 0, ErrorStr); } +void Preprocessor::EndSourceFile() { + // Notify the client that we reached the end of the source file. + if (Callbacks) + Callbacks->EndOfMainFile(); +} //===----------------------------------------------------------------------===// // Lexer Event Handling. diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp index 0795164..51d2e23 100644 --- a/lib/Lex/TokenConcatenation.cpp +++ b/lib/Lex/TokenConcatenation.cpp @@ -85,7 +85,7 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) { TokenInfo[tok::star ] |= aci_avoid_equal; // *= TokenInfo[tok::exclaim ] |= aci_avoid_equal; // != TokenInfo[tok::lessless ] |= aci_avoid_equal; // <<= - TokenInfo[tok::greaterequal] |= aci_avoid_equal; // >>= + TokenInfo[tok::greatergreater] |= aci_avoid_equal; // >>= TokenInfo[tok::caret ] |= aci_avoid_equal; // ^= TokenInfo[tok::equal ] |= aci_avoid_equal; // == } diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index a66dd96..3cd74d5 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -92,7 +92,6 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("dllimport", AT_dllimport) .Case("dllexport", AT_dllexport) .Case("may_alias", IgnoredAttribute) // FIXME: TBAA - .Case("gcc_tdiag", IgnoredAttribute) // GCC diagnostics type checking. .Case("base_check", AT_base_check) .Case("deprecated", AT_deprecated) .Case("visibility", AT_visibility) diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 4a699e7..11865ab 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -481,7 +481,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex) - << CodeModificationHint::CreateInsertion( + << FixItHint::CreateInsertion( PP.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. @@ -507,7 +507,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec) << SpecName - << CodeModificationHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); + << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); ClearStorageClassSpecs(); } diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index f1e639c..87e22fa 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -122,6 +122,9 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param); if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + // Parse the default argument from its saved token stream. Toks->push_back(Tok); // So that the current token doesn't get lost PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); @@ -139,6 +142,15 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { else Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, move(DefArgResult)); + + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseAssignmentExpression went over the default arg tokens!"); + // There could be leftover tokens (e.g. because of an error). + // Skip through until we reach the original token position. + while (Tok.getLocation() != origLoc) + ConsumeAnyToken(); + delete Toks; LM.DefaultArgs[I].Toks = 0; } @@ -177,6 +189,9 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { if (LM.TemplateScope) Actions.ActOnReenterTemplateScope(CurScope, LM.D); + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + assert(!LM.Toks.empty() && "Empty body!"); // Append the current token at the end of the new token stream so that it // doesn't get lost. @@ -195,6 +210,11 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { if (Tok.is(tok::kw_try)) { ParseFunctionTryBlock(LM.D); + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseFunctionTryBlock went over the cached tokens!"); + assert(Tok.getLocation() == origLoc && + "ParseFunctionTryBlock left tokens in the token stream!"); continue; } if (Tok.is(tok::colon)) @@ -204,6 +224,11 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'?? ParseFunctionStatementBody(LM.D); + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "We consumed more than the cached tokens!"); + assert(Tok.getLocation() == origLoc && + "Tokens were left in the token stream!"); } for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index cff35b7..e87d052 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -734,7 +734,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, if (TagName) { Diag(Loc, diag::err_use_of_tag_name_without_tag) << Tok.getIdentifierInfo() << TagName << getLang().CPlusPlus - << CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName); + << FixItHint::CreateInsertion(Tok.getLocation(),TagName); // Parse this as a tag as if the missing tag were present. if (TagKind == tok::kw_enum) @@ -1360,7 +1360,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(EndProtoLoc); Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) - << CodeModificationHint::CreateInsertion(Loc, "id") + << FixItHint::CreateInsertion(Loc, "id") << SourceRange(Loc, EndProtoLoc); // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. @@ -1756,7 +1756,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) - << CodeModificationHint::CreateRemoval(Tok.getLocation()); + << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } @@ -1999,7 +1999,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { !(getLang().C99 || getLang().CPlusPlus0x)) Diag(CommaLoc, diag::ext_enumerator_list_comma) << getLang().CPlusPlus - << CodeModificationHint::CreateRemoval(CommaLoc); + << FixItHint::CreateRemoval(CommaLoc); } // Eat the }. @@ -3009,7 +3009,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // We have ellipsis without a preceding ',', which is ill-formed // in C. Complain and provide the fix. Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis) - << CodeModificationHint::CreateInsertion(EllipsisLoc, ", "); + << FixItHint::CreateInsertion(EllipsisLoc, ", "); } } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 9e232cb..813c24c 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -837,7 +837,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Diag(TemplateId->TemplateNameLoc, diag::err_explicit_instantiation_with_definition) << SourceRange(TemplateInfo.TemplateLoc) - << CodeModificationHint::CreateInsertion(LAngleLoc, "<>"); + << FixItHint::CreateInsertion(LAngleLoc, "<>"); // Create a fake template parameter list that contains only // "template<>", so that we treat this construct as a class @@ -1079,7 +1079,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { if (IsVirtual) { // Complain about duplicate 'virtual' Diag(VirtualLoc, diag::err_dup_virtual) - << CodeModificationHint::CreateRemoval(VirtualLoc); + << FixItHint::CreateRemoval(VirtualLoc); } IsVirtual = true; @@ -1554,7 +1554,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) - << CodeModificationHint::CreateRemoval(Tok.getLocation()); + << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } @@ -1579,10 +1579,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // If attributes exist after class contents, parse them. llvm::OwningPtr<AttributeList> AttrList; if (Tok.is(tok::kw___attribute)) - AttrList.reset(ParseGNUAttributes()); // FIXME: where should I put them? + AttrList.reset(ParseGNUAttributes()); Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl, - LBraceLoc, RBraceLoc); + LBraceLoc, RBraceLoc, + AttrList.get()); // C++ 9.2p2: Within the class member-specification, the class is regarded as // complete within function bodies, default arguments, diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index f1e989f..8528f8f 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -246,7 +246,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // recover like this. PP.LookAhead(1).is(tok::identifier)) { Diag(Next, diag::err_unexected_colon_in_nested_name_spec) - << CodeModificationHint::CreateReplacement(Next.getLocation(), "::"); + << FixItHint::CreateReplacement(Next.getLocation(), "::"); // Recover as if the user wrote '::'. Next.setKind(tok::coloncolon); @@ -1313,7 +1313,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, Diag(TemplateId->TemplateNameLoc, diag::err_out_of_line_constructor_template_id) << TemplateId->Name - << CodeModificationHint::CreateRemoval( + << FixItHint::CreateRemoval( SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); Result.setConstructorName(Actions.getTypeName(*TemplateId->Name, TemplateId->TemplateNameLoc, diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index c4e79ca..9154d8d 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -76,9 +76,8 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { SourceLocation ColonLoc = ConsumeToken(); Diag(Tok, diag::ext_gnu_old_style_field_designator) - << CodeModificationHint::CreateReplacement(SourceRange(NameLoc, - ColonLoc), - NewSyntax.str()); + << FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc), + NewSyntax.str()); Designation D; D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc)); @@ -218,7 +217,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { (Desig.getDesignator(0).isArrayDesignator() || Desig.getDesignator(0).isArrayRangeDesignator())) { Diag(Tok, diag::ext_gnu_missing_equal_designator) - << CodeModificationHint::CreateInsertion(Tok.getLocation(), "= "); + << FixItHint::CreateInsertion(Tok.getLocation(), "= "); return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(), true, ParseInitializer()); } diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 7b2b6e8..9a3473f 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -988,7 +988,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) - << CodeModificationHint::CreateRemoval(Tok.getLocation()); + << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } @@ -1236,7 +1236,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( if (Tok.is(tok::l_brace)) // we have ivars ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, - tok::objc_protected, atLoc); + tok::objc_private, atLoc); ObjCImpDecl = ImplClsType; PendingObjCImpDecl.push_back(ObjCImpDecl); @@ -1571,7 +1571,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { if (Tok.is(tok::semi)) { if (ObjCImpDecl) { Diag(Tok, diag::warn_semicolon_before_method_body) - << CodeModificationHint::CreateRemoval(Tok.getLocation()); + << FixItHint::CreateRemoval(Tok.getLocation()); } ConsumeToken(); } @@ -1817,9 +1817,12 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SkipUntil(tok::r_square); return ExprError(); } - + if (Tok.isNot(tok::r_square)) { - Diag(Tok, diag::err_expected_rsquare); + if (Tok.is(tok::identifier)) + Diag(Tok, diag::err_expected_colon); + else + Diag(Tok, diag::err_expected_rsquare); // We must manually skip to a ']', otherwise the expression skipper will // stop at the ']' when it skips to the ';'. We want it to skip beyond // the enclosing expression. diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 9fd145d..b752b48c 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -125,10 +125,12 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { // expression[opt] ';' OwningExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { - // If the expression is invalid, skip ahead to the next semicolon. Not - // doing this opens us up to the possibility of infinite loops if + // 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::semi); + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); return StmtError(); } // Otherwise, eat the semicolon. diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 12f26bf..ff69953 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -660,7 +660,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, ReplaceStr = "> > "; Diag(Tok.getLocation(), diag::err_two_right_angle_brackets_need_space) - << CodeModificationHint::CreateReplacement( + << FixItHint::CreateReplacement( SourceRange(Tok.getLocation()), ReplaceStr); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index d45aaed..489586c 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -95,8 +95,8 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK, } Diag(Loc, DK) - << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") - << CodeModificationHint::CreateInsertion(EndLoc, ")"); + << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); } /// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'), @@ -146,7 +146,7 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, // Show what code to insert to fix this problem. Diag(EndLoc, DiagID) << Msg - << CodeModificationHint::CreateInsertion(EndLoc, Spelling); + << FixItHint::CreateInsertion(EndLoc, Spelling); } else Diag(Tok, DiagID) << Msg; @@ -395,7 +395,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) case tok::semi: if (!getLang().CPlusPlus0x) Diag(Tok, diag::ext_top_level_semi) - << CodeModificationHint::CreateRemoval(Tok.getLocation()); + << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); // TODO: Invoke action for top-level semicolon. @@ -829,7 +829,7 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { PP.getLocForEndOfToken(Tok.getLocation())); Diag(Tok, diag::warn_file_asm_volatile) - << CodeModificationHint::CreateRemoval(RemovalRange); + << FixItHint::CreateRemoval(RemovalRange); ConsumeToken(); } diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index c4ceec0..d1f00ca 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -154,7 +154,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { continue; } Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (CEE->getType().getNoReturnAttr()) { + if (getFunctionExtInfo(CEE->getType()).getNoReturn()) { NoReturnEdge = true; HasFakeEdge = true; } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { @@ -189,7 +189,7 @@ struct CheckFallThroughDiagnostics { unsigned diag_AlwaysFallThrough_ReturnsNonVoid; unsigned diag_NeverFallThroughOrReturn; bool funMode; - + static CheckFallThroughDiagnostics MakeForFunction() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = @@ -205,7 +205,7 @@ struct CheckFallThroughDiagnostics { D.funMode = true; return D; } - + static CheckFallThroughDiagnostics MakeForBlock() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = @@ -221,7 +221,7 @@ struct CheckFallThroughDiagnostics { D.funMode = false; return D; } - + bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, bool HasNoReturn) const { if (funMode) { @@ -232,7 +232,7 @@ struct CheckFallThroughDiagnostics { && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) == Diagnostic::Ignored || !ReturnsVoid); } - + // For blocks. return ReturnsVoid && !HasNoReturn && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) @@ -255,14 +255,14 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { ReturnsVoid = FD->getResultType()->isVoidType(); HasNoReturn = FD->hasAttr<NoReturnAttr>() || - FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); + FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { ReturnsVoid = MD->getResultType()->isVoidType(); HasNoReturn = MD->hasAttr<NoReturnAttr>(); } else if (isa<BlockDecl>(D)) { - if (const FunctionType *FT = + if (const FunctionType *FT = BlockTy->getPointeeType()->getAs<FunctionType>()) { if (FT->getResultType()->isVoidType()) ReturnsVoid = true; @@ -276,7 +276,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // Short circuit for compilation speed. if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) return; - + // FIXME: Function try block if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { switch (CheckFallThrough(AC)) { @@ -312,25 +312,23 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // warnings on a function, method, or block. //===----------------------------------------------------------------------===// -clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { - Diagnostic &D = S.getDiagnostics(); - +clang::sema::AnalysisBasedWarnings::Policy::Policy() { enableCheckFallThrough = 1; + enableCheckUnreachable = 0; +} - enableCheckUnreachable = (unsigned) +clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { + Diagnostic &D = S.getDiagnostics(); + DefaultPolicy.enableCheckUnreachable = (unsigned) (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored); } -void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, - QualType BlockTy) { - +void clang::sema:: +AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, + const Decl *D, QualType BlockTy, + const bool analyzeStaticInline) { + assert(BlockTy.isNull() || isa<BlockDecl>(D)); - - // Do not do any analysis for declarations in system headers if we are - // going to just ignore them. - if (S.getDiagnostics().getSuppressSystemWarnings() && - S.SourceMgr.isInSystemHeader(D->getLocation())) - return; // We avoid doing analysis-based warnings when there are errors for // two reasons: @@ -339,13 +337,30 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, // (2) The code already has problems; running the analysis just takes more // time. if (S.getDiagnostics().hasErrorOccurred()) - return; - + return; + + // Do not do any analysis for declarations in system headers if we are + // going to just ignore them. + if (S.getDiagnostics().getSuppressSystemWarnings() && + S.SourceMgr.isInSystemHeader(D->getLocation())) + return; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // For function templates, class templates and member function templates // we'll do the analysis at instantiation time. if (FD->isDependentContext()) return; + + // Only analyze 'static inline' functions when explicitly asked. + if (!analyzeStaticInline && FD->isInlineSpecified() && + FD->getStorageClass() == FunctionDecl::Static) { + FD = FD->getCanonicalDecl(); + VisitFlag &visitFlag = VisitedFD[FD]; + if (visitFlag == Pending) + visitFlag = Visited; + else + return; + } } const Stmt *Body = D->getBody(); @@ -354,16 +369,61 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 // explosion for destrutors that can result and the compile time hit. AnalysisContext AC(D, false); + bool performedCheck = false; // Warning: check missing 'return' - if (enableCheckFallThrough) { + if (P.enableCheckFallThrough) { const CheckFallThroughDiagnostics &CD = (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() : CheckFallThroughDiagnostics::MakeForFunction()); CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC); + performedCheck = true; } // Warning: check for unreachable code - if (enableCheckUnreachable) + if (P.enableCheckUnreachable) { CheckUnreachable(S, AC); + performedCheck = true; + } + + // If this block or function calls a 'static inline' function, + // we should analyze those functions as well. + if (performedCheck) { + // The CFG should already be constructed, so this should not + // incur any extra cost. We might not have a CFG, however, for + // invalid code. + if (const CFG *cfg = AC.getCFG()) { + // All CallExprs are block-level expressions in the CFG. This means + // that walking the basic blocks in the CFG is more efficient + // than walking the entire AST to find all calls. + for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) { + const CFGBlock *B = *I; + for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI) + if (const CallExpr *CE = dyn_cast<CallExpr>(*BI)) + if (const DeclRefExpr *DR = + dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenCasts())) + if (const FunctionDecl *calleeD = + dyn_cast<FunctionDecl>(DR->getDecl())) { + calleeD = calleeD->getCanonicalDecl(); + if (calleeD->isInlineSpecified() && + calleeD->getStorageClass() == FunctionDecl::Static) { + // Have we analyzed this static inline function before? + VisitFlag &visitFlag = VisitedFD[calleeD]; + if (visitFlag == NotVisited) { + // Mark the callee visited prior to analyzing it + // so we terminate in case of recursion. + if (calleeD->getBody()) { + visitFlag = Visited; + IssueWarnings(DefaultPolicy, calleeD, QualType(), true); + } + else { + // Delay warnings until we encounter the definition. + visitFlag = Pending; + } + } + } + } + } + } + } } diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h index 39da1b1..b5db8af 100644 --- a/lib/Sema/AnalysisBasedWarnings.h +++ b/lib/Sema/AnalysisBasedWarnings.h @@ -14,22 +14,44 @@ #ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H #define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H -namespace clang { namespace sema { +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class Sema; + +namespace sema { class AnalysisBasedWarnings { - Sema &S; - // The warnings to run. - unsigned enableCheckFallThrough : 1; - unsigned enableCheckUnreachable : 1; - public: + class Policy { + friend class AnalysisBasedWarnings; + // The warnings to run. + unsigned enableCheckFallThrough : 1; + unsigned enableCheckUnreachable : 1; + public: + Policy(); + void disableCheckFallThrough() { enableCheckFallThrough = 0; } + }; + +private: + Sema &S; + Policy DefaultPolicy; + enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 }; + llvm::DenseMap<const FunctionDecl*, VisitFlag> VisitedFD; + +public: AnalysisBasedWarnings(Sema &s); - void IssueWarnings(const Decl *D, QualType BlockTy = QualType()); - - void disableCheckFallThrough() { enableCheckFallThrough = 0; } + + Policy getDefaultPolicy() { return DefaultPolicy; } + + void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType(), + const bool analyzeStaticInline = false); + }; - + }} // end namespace clang::sema #endif diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index 6b26945..f310c25 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -397,6 +397,12 @@ public: configure(); } + /// \brief Change this lookup's redeclaration kind. + void setRedeclarationKind(Sema::RedeclarationKind RK) { + Redecl = RK; + configure(); + } + void print(llvm::raw_ostream &); /// Suppress the diagnostics that would normally fire because of this diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 7112687..ccfbe1e 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -132,7 +132,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), NonInstantiationEntries(0), - CurrentInstantiationScope(0), TyposCorrected(0) + CurrentInstantiationScope(0), TyposCorrected(0), + AnalysisWarnings(*this) { TUScope = 0; if (getLangOptions().CPlusPlus) @@ -347,6 +348,30 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { } } +Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID) { + if (isSFINAEContext()) { + switch (Diagnostic::getDiagnosticSFINAEResponse(DiagID)) { + case Diagnostic::SFINAE_Report: + // Fall through; we'll report the diagnostic below. + break; + + case Diagnostic::SFINAE_SubstitutionFailure: + // Count this failure so that we know that template argument deduction + // has failed. + ++NumSFINAEErrors; + // Fall through + + case Diagnostic::SFINAE_Suppress: + // Suppress this diagnostic. + Diags.setLastDiagnosticIgnored(); + return SemaDiagnosticBuilder(*this); + } + } + + DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); + return SemaDiagnosticBuilder(DB, *this, DiagID); +} + Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID())); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b529e5b..0766b1e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -19,6 +19,7 @@ #include "CXXFieldCollector.h" #include "SemaOverload.h" #include "SemaTemplate.h" +#include "AnalysisBasedWarnings.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclBase.h" #include "clang/AST/Decl.h" @@ -298,7 +299,7 @@ public: /// \brief The set of static functions seen so far that have not been used. std::vector<FunctionDecl*> UnusedStaticFuncs; - + class AccessedEntity { public: /// A member declaration found through lookup. The target is the @@ -311,30 +312,33 @@ public: bool isMemberAccess() const { return IsMember; } - AccessedEntity(MemberNonce _, + AccessedEntity(ASTContext &Context, + MemberNonce _, CXXRecordDecl *NamingClass, AccessSpecifier Access, NamedDecl *Target) : Access(Access), IsMember(true), Target(Target), NamingClass(NamingClass), - Diag(0) { + Diag(0, Context.getDiagAllocator()) { } - AccessedEntity(MemberNonce _, + AccessedEntity(ASTContext &Context, + MemberNonce _, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl) : Access(FoundDecl.getAccess()), IsMember(true), Target(FoundDecl.getDecl()), NamingClass(NamingClass), - Diag(0) { + Diag(0, Context.getDiagAllocator()) { } - AccessedEntity(BaseNonce _, + AccessedEntity(ASTContext &Context, + BaseNonce _, CXXRecordDecl *BaseClass, CXXRecordDecl *DerivedClass, AccessSpecifier Access) : Access(Access), IsMember(false), Target(BaseClass), NamingClass(DerivedClass), - Diag(0) { + Diag(0, Context.getDiagAllocator()) { } bool isQuiet() const { return Diag.getDiagID() == 0; } @@ -362,7 +366,7 @@ public: PartialDiagnostic &setDiag(unsigned DiagID) { assert(isQuiet() && "partial diagnostic already defined"); assert(DiagID && "creating null diagnostic"); - Diag = PartialDiagnostic(DiagID); + Diag.Reset(DiagID); return Diag; } const PartialDiagnostic &getDiag() const { @@ -609,23 +613,16 @@ public: }; /// \brief Emit a diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { - if (isSFINAEContext() && Diagnostic::isBuiltinSFINAEDiag(DiagID)) { - // If we encountered an error during template argument - // deduction, and that error is one of the SFINAE errors, - // suppress the diagnostic. - ++NumSFINAEErrors; - Diags.setLastDiagnosticIgnored(); - return SemaDiagnosticBuilder(*this); - } - - DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); - return SemaDiagnosticBuilder(DB, *this, DiagID); - } + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); /// \brief Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); + /// \brief Build a partial diagnostic. + PartialDiagnostic PDiag(unsigned DiagID = 0) { + return PartialDiagnostic(DiagID, Context.getDiagAllocator()); + } + virtual void DeleteExpr(ExprTy *E); virtual void DeleteStmt(StmtTy *S); @@ -727,6 +724,7 @@ public: const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingExceptionSpecification = 0, bool *MissingEmptyExceptionSpecification = 0); bool CheckExceptionSpecSubset( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, @@ -742,10 +740,12 @@ public: bool RequireCompleteType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD, - std::pair<SourceLocation, - PartialDiagnostic> Note = - std::make_pair(SourceLocation(), PDiag())); - + std::pair<SourceLocation, PartialDiagnostic> Note); + bool RequireCompleteType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD); + bool RequireCompleteType(SourceLocation Loc, QualType T, + unsigned DiagID); + QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E); @@ -783,7 +783,8 @@ public: const LookupResult &Previous, Scope *S); void DiagnoseFunctionSpecifiers(Declarator& D); - void DiagnoseShadow(Scope *S, Declarator &D, const LookupResult& R); + void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); + void CheckShadow(Scope *S, VarDecl *D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration); @@ -827,6 +828,7 @@ public: virtual void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init); void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit); void ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto); + virtual void ActOnInitializerError(DeclPtrTy Dcl); virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc); virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, DeclPtrTy *Group, @@ -1110,9 +1112,6 @@ public: bool SuppressUserConversions, bool ForceRValue, bool InOverloadResolution); - bool PerformCopyInitialization(Expr *&From, QualType ToType, - AssignmentAction Action, bool Elidable = false); - OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, OwningExprResult Init); @@ -1121,6 +1120,7 @@ public: CXXRecordDecl *ActingContext); bool PerformObjectArgumentInitialization(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, CXXMethodDecl *Method); ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); @@ -1128,6 +1128,7 @@ public: bool PerformObjectMemberConversion(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, NamedDecl *Member); // Members have to be NamespaceDecl* or TranslationUnitDecl*. @@ -1248,11 +1249,15 @@ public: const PartialDiagnostic &PDiag); FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, - bool Complain); + bool Complain, + DeclAccessPair &Found); FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From); - Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + Expr *FixOverloadedFunctionReference(Expr *E, + NamedDecl *FoundDecl, + FunctionDecl *Fn); OwningExprResult FixOverloadedFunctionReference(OwningExprResult, + NamedDecl *FoundDecl, FunctionDecl *Fn); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, @@ -1448,7 +1453,7 @@ public: void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList); void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, - bool &IncompleteImpl); + bool &IncompleteImpl, unsigned DiagID); void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod, ObjCMethodDecl *IntfMethod); @@ -1464,7 +1469,7 @@ public: bool& IncompleteImpl, const llvm::DenseSet<Selector> &InsMap, const llvm::DenseSet<Selector> &ClsMap, - ObjCInterfaceDecl *IDecl); + ObjCContainerDecl *CDecl); /// CheckImplementationIvars - This routine checks if the instance variables /// listed in the implelementation match those listed in the interface. @@ -2397,7 +2402,9 @@ public: Expr *BuildObjCEncodeExpression(SourceLocation AtLoc, QualType EncodedType, SourceLocation RParenLoc); - CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method); + CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, + NamedDecl *FoundDecl, + CXXMethodDecl *Method); virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, @@ -2471,9 +2478,7 @@ public: bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers, - bool IsImplicitConstructor, - bool AnyErrors); + unsigned NumInitializers, bool AnyErrors); /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, /// mark all the non-trivial destructors of its members and bases as @@ -2495,7 +2500,8 @@ public: /// MarkVirtualMembersReferenced - Will mark all virtual members of the given /// CXXRecordDecl referenced. - void MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD); + void MarkVirtualMembersReferenced(SourceLocation Loc, + const CXXRecordDecl *RD); /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes /// that might need to have their virtual members marked as referenced. @@ -2513,7 +2519,8 @@ public: virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, - SourceLocation RBrac); + SourceLocation RBrac, + AttributeList *AttrList); virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template); virtual void ActOnStartDelayedMemberDeclarations(Scope *S, @@ -2640,15 +2647,21 @@ public: Expr *ObjectExpr, Expr *ArgExpr, DeclAccessPair FoundDecl); + AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, + DeclAccessPair FoundDecl); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, QualType Base, QualType Derived, const CXXBasePath &Path, unsigned DiagID, bool ForceCheck = false, bool ForceUnprivileged = false); - void CheckLookupAccess(const LookupResult &R); + void HandleDependentAccessCheck(const DependentDiagnostic &DD, + const MultiLevelTemplateArgumentList &TemplateArgs); + void PerformDependentDiagnostics(const DeclContext *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs); + void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx); enum AbstractDiagSelID { @@ -2869,12 +2882,29 @@ public: Decl *Param, TemplateArgumentListBuilder &Converted); + /// \brief Specifies the context in which a particular template + /// argument is being checked. + enum CheckTemplateArgumentKind { + /// \brief The template argument was specified in the code or was + /// instantiated with some deduced template arguments. + CTAK_Specified, + + /// \brief The template argument was deduced via template argument + /// deduction. + CTAK_Deduced, + + /// \brief The template argument was deduced from an array bound + /// via template argument deduction. + CTAK_DeducedFromArrayBound + }; + bool CheckTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &Arg, TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, - TemplateArgumentListBuilder &Converted); + TemplateArgumentListBuilder &Converted, + CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, @@ -2888,15 +2918,22 @@ public: bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); - bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, - NamedDecl *&Entity); bool CheckTemplateArgumentPointerToMember(Expr *Arg, TemplateArgument &Converted); bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, - TemplateArgument &Converted); + TemplateArgument &Converted, + CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, const TemplateArgumentLoc &Arg); + + OwningExprResult + BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, + QualType ParamType, + SourceLocation Loc); + OwningExprResult + BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, + SourceLocation Loc); /// \brief Enumeration describing how template parameter lists are compared /// for equality. @@ -3119,14 +3156,15 @@ public: TemplateDeductionResult SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, const TemplateArgumentListInfo &ExplicitTemplateArgs, - llvm::SmallVectorImpl<TemplateArgument> &Deduced, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, llvm::SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, TemplateDeductionInfo &Info); TemplateDeductionResult FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl<TemplateArgument> &Deduced, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, TemplateDeductionInfo &Info); @@ -3480,15 +3518,27 @@ public: /// \brief Whether we have already exited this scope. bool Exited; + /// \brief Whether this scope is temporary, meaning that we should + /// remove any additions we make once we exit this + /// scope. Temporary scopes are always combined with their outer + /// scopes. + bool Temporary; + + /// \brief List of the declarations that we have added into this + /// temporary scope. They will be removed when we exit the + /// temporary scope. + llvm::SmallVector<const Decl *, 4> AddedTemporaryDecls; + // This class is non-copyable LocalInstantiationScope(const LocalInstantiationScope &); LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: - LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false, + bool Temporary = false) : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), - Exited(false) { - if (!CombineWithOuterScope) + Exited(false), Temporary(Temporary) { + if (!CombineWithOuterScope && !Temporary) SemaRef.CurrentInstantiationScope = this; else assert(SemaRef.CurrentInstantiationScope && @@ -3496,8 +3546,11 @@ public: } ~LocalInstantiationScope() { - if (!Exited) + if (!Exited) { SemaRef.CurrentInstantiationScope = Outer; + for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I) + LocalDecls.erase(AddedTemporaryDecls[I]); + } } /// \brief Exit this local instantiation scope early. @@ -3530,6 +3583,10 @@ public: void InstantiatedLocal(const Decl *D, Decl *Inst) { Decl *&Stored = LocalDecls[D]; assert((!Stored || Stored == Inst) && "Already instantiated this local"); + + if (Temporary && !Stored) + AddedTemporaryDecls.push_back(D); + Stored = Inst; } }; @@ -3541,6 +3598,9 @@ public: /// \brief The number of typos corrected by CorrectTypo. unsigned TyposCorrected; + /// \brief Worker object for performing CFG-based warnings. + sema::AnalysisBasedWarnings AnalysisWarnings; + /// \brief An entity for which implicit template instantiation is required. /// /// The source location associated with the declaration is the first place in @@ -3714,7 +3774,7 @@ public: /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \arg PropertyTy. - void CheckObjCPropertyAttributes(QualType PropertyTy, + void CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy, SourceLocation Loc, unsigned &Attributes); void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC); diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 40b320c..f628884 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -17,6 +17,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" +#include "clang/AST/DependentDiagnostic.h" #include "clang/AST/ExprCXX.h" using namespace clang; @@ -52,136 +53,323 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, namespace { struct EffectiveContext { - EffectiveContext() : Function(0) {} + EffectiveContext() : Inner(0), Dependent(false) {} - explicit EffectiveContext(DeclContext *DC) { - if (isa<FunctionDecl>(DC)) { - Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); - DC = Function->getDeclContext(); - } else - Function = 0; + explicit EffectiveContext(DeclContext *DC) + : Inner(DC), + Dependent(DC->isDependentContext()) { // C++ [class.access.nest]p1: // A nested class is a member and as such has the same access // rights as any other member. // C++ [class.access]p2: // A member of a class can also access all the names to which - // the class has access. - // This implies that the privileges of nesting are transitive. - while (isa<CXXRecordDecl>(DC)) { - CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); - Records.push_back(Record); - DC = Record->getDeclContext(); + // the class has access. A local class of a member function + // may access the same names that the member function itself + // may access. + // This almost implies that the privileges of nesting are transitive. + // Technically it says nothing about the local classes of non-member + // functions (which can gain privileges through friendship), but we + // take that as an oversight. + while (true) { + if (isa<CXXRecordDecl>(DC)) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); + Records.push_back(Record); + DC = Record->getDeclContext(); + } else if (isa<FunctionDecl>(DC)) { + FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); + Functions.push_back(Function); + DC = Function->getDeclContext(); + } else if (DC->isFileContext()) { + break; + } else { + DC = DC->getParent(); + } } } + bool isDependent() const { return Dependent; } + bool includesClass(const CXXRecordDecl *R) const { R = R->getCanonicalDecl(); return std::find(Records.begin(), Records.end(), R) != Records.end(); } + /// Retrieves the innermost "useful" context. Can be null if we're + /// doing access-control without privileges. + DeclContext *getInnerContext() const { + return Inner; + } + + typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; + + DeclContext *Inner; + llvm::SmallVector<FunctionDecl*, 4> Functions; llvm::SmallVector<CXXRecordDecl*, 4> Records; - FunctionDecl *Function; + bool Dependent; }; } static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { - CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext()); + DeclContext *DC = D->getDeclContext(); + + // This can only happen at top: enum decls only "publish" their + // immediate members. + if (isa<EnumDecl>(DC)) + DC = cast<EnumDecl>(DC)->getDeclContext(); + + CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); while (DeclaringClass->isAnonymousStructOrUnion()) DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); return DeclaringClass; } +static bool MightInstantiateTo(Sema &S, DeclContext *Context, + DeclContext *Friend) { + if (Friend == Context) + return true; + + assert(!Friend->isDependentContext() && + "can't handle friends with dependent contexts here"); + + if (!Context->isDependentContext()) + return false; + + if (Friend->isFileContext()) + return false; + + // TODO: this is very conservative + return true; +} + +// Asks whether the type in 'context' can ever instantiate to the type +// in 'friend'. +static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) { + if (Friend == Context) + return true; + + if (!Friend->isDependentType() && !Context->isDependentType()) + return false; + + // TODO: this is very conservative. + return true; +} + +static bool MightInstantiateTo(Sema &S, + FunctionDecl *Context, + FunctionDecl *Friend) { + if (Context->getDeclName() != Friend->getDeclName()) + return false; + + if (!MightInstantiateTo(S, + Context->getDeclContext(), + Friend->getDeclContext())) + return false; + + CanQual<FunctionProtoType> FriendTy + = S.Context.getCanonicalType(Friend->getType()) + ->getAs<FunctionProtoType>(); + CanQual<FunctionProtoType> ContextTy + = S.Context.getCanonicalType(Context->getType()) + ->getAs<FunctionProtoType>(); + + // There isn't any way that I know of to add qualifiers + // during instantiation. + if (FriendTy.getQualifiers() != ContextTy.getQualifiers()) + return false; + + if (FriendTy->getNumArgs() != ContextTy->getNumArgs()) + return false; + + if (!MightInstantiateTo(S, + ContextTy->getResultType(), + FriendTy->getResultType())) + return false; + + for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I) + if (!MightInstantiateTo(S, + ContextTy->getArgType(I), + FriendTy->getArgType(I))) + return false; + + return true; +} + +static bool MightInstantiateTo(Sema &S, + FunctionTemplateDecl *Context, + FunctionTemplateDecl *Friend) { + return MightInstantiateTo(S, + Context->getTemplatedDecl(), + Friend->getTemplatedDecl()); +} + static Sema::AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *Friend) { - // FIXME: close matches becuse of dependency if (EC.includesClass(Friend)) return Sema::AR_accessible; + if (EC.isDependent()) { + CanQualType FriendTy + = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend)); + + for (EffectiveContext::record_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + CanQualType ContextTy + = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); + if (MightInstantiateTo(S, ContextTy, FriendTy)) + return Sema::AR_dependent; + } + } + return Sema::AR_inaccessible; } static Sema::AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, - FriendDecl *Friend) { - if (Type *T = Friend->getFriendType()) { - CanQualType CT = T->getCanonicalTypeUnqualified(); - if (const RecordType *RT = CT->getAs<RecordType>()) - return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); - - // TODO: we can fail early for a lot of type classes. - if (T->isDependentType()) - return Sema::AR_dependent; + CanQualType Friend) { + if (const RecordType *RT = Friend->getAs<RecordType>()) + return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); - return Sema::AR_inaccessible; - } + // TODO: we can do better than this + if (Friend->isDependentType()) + return Sema::AR_dependent; - NamedDecl *D - = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl()); + return Sema::AR_inaccessible; +} - // FIXME: declarations with dependent or templated scope. +/// Determines whether the given friend class template matches +/// anything in the effective context. +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + ClassTemplateDecl *Friend) { + Sema::AccessResult OnFailure = Sema::AR_inaccessible; - // For class templates, we want to check whether any of the records - // are possible specializations of the template. - if (isa<ClassTemplateDecl>(D)) { - for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator - I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { - CXXRecordDecl *Record = *I; - ClassTemplateDecl *CTD; + // Check whether the friend is the template of a class in the + // context chain. + for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + CXXRecordDecl *Record = *I; - // A specialization of the template... - if (isa<ClassTemplateSpecializationDecl>(Record)) { - CTD = cast<ClassTemplateSpecializationDecl>(Record) - ->getSpecializedTemplate(); + // Figure out whether the current class has a template: + ClassTemplateDecl *CTD; - // ... or the template pattern itself. - } else { - CTD = Record->getDescribedClassTemplate(); - } + // A specialization of the template... + if (isa<ClassTemplateSpecializationDecl>(Record)) { + CTD = cast<ClassTemplateSpecializationDecl>(Record) + ->getSpecializedTemplate(); - if (CTD && D == CTD->getCanonicalDecl()) - return Sema::AR_accessible; + // ... or the template pattern itself. + } else { + CTD = Record->getDescribedClassTemplate(); + if (!CTD) continue; } - return Sema::AR_inaccessible; + // It's a match. + if (Friend == CTD->getCanonicalDecl()) + return Sema::AR_accessible; + + // If the context isn't dependent, it can't be a dependent match. + if (!EC.isDependent()) + continue; + + // If the template names don't match, it can't be a dependent + // match. This isn't true in C++0x because of template aliases. + if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) + continue; + + // If the class's context can't instantiate to the friend's + // context, it can't be a dependent match. + if (!MightInstantiateTo(S, CTD->getDeclContext(), + Friend->getDeclContext())) + continue; + + // Otherwise, it's a dependent match. + OnFailure = Sema::AR_dependent; + } + + return OnFailure; +} + +/// Determines whether the given friend function matches anything in +/// the effective context. +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FunctionDecl *Friend) { + Sema::AccessResult OnFailure = Sema::AR_inaccessible; + + for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator + I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { + if (Friend == *I) + return Sema::AR_accessible; + + if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) + OnFailure = Sema::AR_dependent; } - // Same thing for function templates. - if (isa<FunctionTemplateDecl>(D)) { - if (!EC.Function) return Sema::AR_inaccessible; + return OnFailure; +} + +/// Determines whether the given friend function template matches +/// anything in the effective context. +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FunctionTemplateDecl *Friend) { + if (EC.Functions.empty()) return Sema::AR_inaccessible; - FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate(); + Sema::AccessResult OnFailure = Sema::AR_inaccessible; + + for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator + I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { + + FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); if (!FTD) - FTD = EC.Function->getDescribedFunctionTemplate(); + FTD = (*I)->getDescribedFunctionTemplate(); + if (!FTD) + continue; + + FTD = FTD->getCanonicalDecl(); - if (FTD && D == FTD->getCanonicalDecl()) + if (Friend == FTD) return Sema::AR_accessible; - - return Sema::AR_inaccessible; + + if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) + OnFailure = Sema::AR_dependent; } - // Friend functions. FIXME: close matches due to dependency. - // - // The decl pointers in EC have been canonicalized, so pointer - // equality is sufficient. - if (D == EC.Function) - return Sema::AR_accessible; + return OnFailure; +} - if (isa<CXXRecordDecl>(D)) - return MatchesFriend(S, EC, cast<CXXRecordDecl>(D)); +/// Determines whether the given friend declaration matches anything +/// in the effective context. +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FriendDecl *FriendD) { + if (TypeSourceInfo *T = FriendD->getFriendType()) + return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); - return Sema::AR_inaccessible; + NamedDecl *Friend + = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl()); + + // FIXME: declarations with dependent or templated scope. + + if (isa<ClassTemplateDecl>(Friend)) + return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend)); + + if (isa<FunctionTemplateDecl>(Friend)) + return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend)); + + if (isa<CXXRecordDecl>(Friend)) + return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend)); + + assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind"); + return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); } static Sema::AccessResult GetFriendKind(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *Class) { - // A class always has access to its own members. - if (EC.includesClass(Class)) - return Sema::AR_accessible; - Sema::AccessResult OnFailure = Sema::AR_inaccessible; // Okay, check friends. @@ -209,9 +397,88 @@ static Sema::AccessResult GetFriendKind(Sema &S, return OnFailure; } +static Sema::AccessResult HasAccess(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *NamingClass, + AccessSpecifier Access) { + assert(NamingClass->getCanonicalDecl() == NamingClass && + "declaration should be canonicalized before being passed here"); + + if (Access == AS_public) return Sema::AR_accessible; + assert(Access == AS_private || Access == AS_protected); + + for (EffectiveContext::record_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + // All the declarations in EC have been canonicalized, so pointer + // equality from this point on will work fine. + const CXXRecordDecl *ECRecord = *I; + + // [B2] and [M2] + if (ECRecord == NamingClass) + return Sema::AR_accessible; + + // [B3] and [M3] + if (Access == AS_protected && + ECRecord->isDerivedFrom(const_cast<CXXRecordDecl*>(NamingClass))) + return Sema::AR_accessible; + } + + return GetFriendKind(S, EC, NamingClass); +} + /// Finds the best path from the naming class to the declaring class, /// taking friend declarations into account. /// +/// C++0x [class.access.base]p5: +/// A member m is accessible at the point R when named in class N if +/// [M1] m as a member of N is public, or +/// [M2] m as a member of N is private, and R occurs in a member or +/// friend of class N, or +/// [M3] m as a member of N is protected, and R occurs in a member or +/// friend of class N, or in a member or friend of a class P +/// derived from N, where m as a member of P is public, private, +/// or protected, or +/// [M4] there exists a base class B of N that is accessible at R, and +/// m is accessible at R when named in class B. +/// +/// C++0x [class.access.base]p4: +/// A base class B of N is accessible at R, if +/// [B1] an invented public member of B would be a public member of N, or +/// [B2] R occurs in a member or friend of class N, and an invented public +/// member of B would be a private or protected member of N, or +/// [B3] R occurs in a member or friend of a class P derived from N, and an +/// invented public member of B would be a private or protected member +/// of P, or +/// [B4] there exists a class S such that B is a base class of S accessible +/// at R and S is a base class of N accessible at R. +/// +/// Along a single inheritance path we can restate both of these +/// iteratively: +/// +/// First, we note that M1-4 are equivalent to B1-4 if the member is +/// treated as a notional base of its declaring class with inheritance +/// access equivalent to the member's access. Therefore we need only +/// ask whether a class B is accessible from a class N in context R. +/// +/// Let B_1 .. B_n be the inheritance path in question (i.e. where +/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of +/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the +/// closest accessible base in the path: +/// Access(a, b) = (* access on the base specifier from a to b *) +/// Merge(a, forbidden) = forbidden +/// Merge(a, private) = forbidden +/// Merge(a, b) = min(a,b) +/// Accessible(c, forbidden) = false +/// Accessible(c, private) = (R is c) || IsFriend(c, R) +/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R) +/// Accessible(c, public) = true +/// ACAB(n) = public +/// ACAB(i) = +/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in +/// if Accessible(B_i, AccessToBase) then public else AccessToBase +/// +/// B is an accessible base of N at R iff ACAB(1) = public. +/// /// \param FinalAccess the access of the "final step", or AS_none if /// there is no final step. /// \return null if friendship is dependent @@ -230,6 +497,8 @@ static CXXBasePath *FindBestPath(Sema &S, assert(FinalAccess != AS_none && "forbidden access after declaring class"); + bool AnyDependent = false; + // Derive the friend-modified access along each path. for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); PI != PE; ++PI) { @@ -251,19 +520,15 @@ static CXXBasePath *FindBestPath(Sema &S, } AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); - if (BaseAccess != AS_public) { - switch (GetFriendKind(S, EC, I->Class)) { - case Sema::AR_inaccessible: - PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess); - break; - case Sema::AR_accessible: - PathAccess = AS_public; - break; - case Sema::AR_dependent: - return 0; - case Sema::AR_delayed: - llvm_unreachable("friend resolution is never delayed"); break; - } + PathAccess = std::max(PathAccess, BaseAccess); + switch (HasAccess(S, EC, I->Class, PathAccess)) { + case Sema::AR_inaccessible: break; + case Sema::AR_accessible: PathAccess = AS_public; break; + case Sema::AR_dependent: + AnyDependent = true; + goto Next; + case Sema::AR_delayed: + llvm_unreachable("friend resolution is never delayed"); break; } } @@ -272,9 +537,23 @@ static CXXBasePath *FindBestPath(Sema &S, if (BestPath == 0 || PathAccess < BestPath->Access) { BestPath = &*PI; BestPath->Access = PathAccess; + + // Short-circuit if we found a public path. + if (BestPath->Access == AS_public) + return BestPath; } + + Next: ; } + assert((!BestPath || BestPath->Access != AS_public) && + "fell out of loop with public path"); + + // We didn't find a public path, but at least one path was subject + // to dependent friendship, so delay the check. + if (AnyDependent) + return 0; + return BestPath; } @@ -282,16 +561,27 @@ static CXXBasePath *FindBestPath(Sema &S, /// to become inaccessible. static void DiagnoseAccessPath(Sema &S, const EffectiveContext &EC, - CXXRecordDecl *NamingClass, - CXXRecordDecl *DeclaringClass, - NamedDecl *D, AccessSpecifier Access) { + const Sema::AccessedEntity &Entity) { + AccessSpecifier Access = Entity.getAccess(); + CXXRecordDecl *NamingClass = Entity.getNamingClass(); + NamingClass = NamingClass->getCanonicalDecl(); + + NamedDecl *D; + CXXRecordDecl *DeclaringClass; + if (Entity.isMemberAccess()) { + D = Entity.getTargetDecl(); + DeclaringClass = FindDeclaringClass(D); + } else { + D = 0; + DeclaringClass = Entity.getBaseClass(); + } + DeclaringClass = DeclaringClass->getCanonicalDecl(); + // Easy case: the decl's natural access determined its path access. // We have to check against AS_private here in case Access is AS_none, // indicating a non-public member of a private base class. - // - // DependentFriend should be impossible here. if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) { - switch (GetFriendKind(S, EC, DeclaringClass)) { + switch (HasAccess(S, EC, DeclaringClass, D->getAccess())) { case Sema::AR_inaccessible: { S.Diag(D->getLocation(), diag::note_access_natural) << (unsigned) (Access == AS_protected) @@ -357,144 +647,166 @@ static void DiagnoseAccessPath(Sema &S, llvm_unreachable("access not apparently constrained by path"); } -/// Diagnose an inaccessible class member. -static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc, - const EffectiveContext &EC, - CXXRecordDecl *NamingClass, - AccessSpecifier Access, - const Sema::AccessedEntity &Entity) { - NamedDecl *D = Entity.getTargetDecl(); - CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); +static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, + const EffectiveContext &EC, + const Sema::AccessedEntity &Entity) { + const CXXRecordDecl *NamingClass = Entity.getNamingClass(); + NamedDecl *D; + const CXXRecordDecl *DeclaringClass; + if (Entity.isMemberAccess()) { + D = Entity.getTargetDecl(); + DeclaringClass = FindDeclaringClass(D); + } else { + D = 0; + DeclaringClass = Entity.getBaseClass(); + } S.Diag(Loc, Entity.getDiag()) - << (Access == AS_protected) - << D->getDeclName() + << (Entity.getAccess() == AS_protected) + << (D ? D->getDeclName() : DeclarationName()) << S.Context.getTypeDeclType(NamingClass) << S.Context.getTypeDeclType(DeclaringClass); - DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access); + DiagnoseAccessPath(S, EC, Entity); } -/// Diagnose an inaccessible hierarchy conversion. -static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc, - const EffectiveContext &EC, - AccessSpecifier Access, - const Sema::AccessedEntity &Entity) { - S.Diag(Loc, Entity.getDiag()) - << (Access == AS_protected) - << DeclarationName() - << S.Context.getTypeDeclType(Entity.getDerivedClass()) - << S.Context.getTypeDeclType(Entity.getBaseClass()); - DiagnoseAccessPath(S, EC, Entity.getDerivedClass(), - Entity.getBaseClass(), 0, Access); -} +/// Determines whether the accessed entity is accessible. Public members +/// have been weeded out by this point. +static Sema::AccessResult IsAccessible(Sema &S, + const EffectiveContext &EC, + const Sema::AccessedEntity &Entity) { + // Determine the actual naming class. + CXXRecordDecl *NamingClass = Entity.getNamingClass(); + while (NamingClass->isAnonymousStructOrUnion()) + NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); + NamingClass = NamingClass->getCanonicalDecl(); -static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, - const EffectiveContext &EC, - CXXRecordDecl *NamingClass, - AccessSpecifier Access, - const Sema::AccessedEntity &Entity) { - if (Entity.isMemberAccess()) - DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity); - else - DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity); -} + AccessSpecifier UnprivilegedAccess = Entity.getAccess(); + assert(UnprivilegedAccess != AS_public && "public access not weeded out"); + // Before we try to recalculate access paths, try to white-list + // accesses which just trade in on the final step, i.e. accesses + // which don't require [M4] or [B4]. These are by far the most + // common forms of access. + if (UnprivilegedAccess != AS_none) { + switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess)) { + case Sema::AR_dependent: + // This is actually an interesting policy decision. We don't + // *have* to delay immediately here: we can do the full access + // calculation in the hope that friendship on some intermediate + // class will make the declaration accessible non-dependently. + // But that's not cheap, and odds are very good (note: assertion + // made without data) that the friend declaration will determine + // access. + return Sema::AR_dependent; + + case Sema::AR_accessible: return Sema::AR_accessible; + case Sema::AR_inaccessible: break; + case Sema::AR_delayed: + llvm_unreachable("friendship never subject to contextual delay"); + } + } -/// Try to elevate access using friend declarations. This is -/// potentially quite expensive. -static void TryElevateAccess(Sema &S, - const EffectiveContext &EC, - const Sema::AccessedEntity &Entity, - AccessSpecifier &Access) { + // Determine the declaring class. CXXRecordDecl *DeclaringClass; if (Entity.isMemberAccess()) { DeclaringClass = FindDeclaringClass(Entity.getTargetDecl()); } else { DeclaringClass = Entity.getBaseClass(); } - CXXRecordDecl *NamingClass = Entity.getNamingClass(); + DeclaringClass = DeclaringClass->getCanonicalDecl(); + + // We lower member accesses to base accesses by pretending that the + // member is a base class of its declaring class. + AccessSpecifier FinalAccess; - // Adjust the declaration of the referred entity. - AccessSpecifier DeclAccess = AS_public; if (Entity.isMemberAccess()) { + // Determine if the declaration is accessible from EC when named + // in its declaring class. NamedDecl *Target = Entity.getTargetDecl(); - DeclAccess = Target->getAccess(); - if (DeclAccess != AS_public) { - switch (GetFriendKind(S, EC, DeclaringClass)) { - case Sema::AR_accessible: DeclAccess = AS_public; break; - case Sema::AR_inaccessible: break; - case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return; - case Sema::AR_delayed: llvm_unreachable("friend status is never delayed"); - } + FinalAccess = Target->getAccess(); + switch (HasAccess(S, EC, DeclaringClass, FinalAccess)) { + case Sema::AR_accessible: FinalAccess = AS_public; break; + case Sema::AR_inaccessible: break; + case Sema::AR_dependent: return Sema::AR_dependent; // see above + case Sema::AR_delayed: llvm_unreachable("friend status is never delayed"); } - if (DeclaringClass == NamingClass) { - Access = DeclAccess; - return; - } + if (DeclaringClass == NamingClass) + return (FinalAccess == AS_public + ? Sema::AR_accessible + : Sema::AR_inaccessible); + } else { + FinalAccess = AS_public; } assert(DeclaringClass != NamingClass); // Append the declaration's access if applicable. CXXBasePaths Paths; - CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(), - DeclaringClass, DeclAccess, Paths); - if (!Path) { - // FIXME: delay dependent friendship - return; - } + CXXBasePath *Path = FindBestPath(S, EC, NamingClass, DeclaringClass, + FinalAccess, Paths); + if (!Path) + return Sema::AR_dependent; + + assert(Path->Access <= UnprivilegedAccess && + "access along best path worse than direct?"); + if (Path->Access == AS_public) + return Sema::AR_accessible; + return Sema::AR_inaccessible; +} - // Grab the access along the best path (note that this includes the - // final-step access). - AccessSpecifier NewAccess = Path->Access; - assert(NewAccess <= Access && "access along best path worse than direct?"); - Access = NewAccess; +static void DelayAccess(Sema &S, + const EffectiveContext &EC, + SourceLocation Loc, + const Sema::AccessedEntity &Entity) { + assert(EC.isDependent() && "delaying non-dependent access"); + DeclContext *DC = EC.getInnerContext(); + assert(DC->isDependentContext() && "delaying non-dependent access"); + DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access, + Loc, + Entity.isMemberAccess(), + Entity.getAccess(), + Entity.getTargetDecl(), + Entity.getNamingClass(), + Entity.getDiag()); } /// Checks access to an entity from the given effective context. static Sema::AccessResult CheckEffectiveAccess(Sema &S, const EffectiveContext &EC, SourceLocation Loc, - Sema::AccessedEntity const &Entity) { - AccessSpecifier Access = Entity.getAccess(); - assert(Access != AS_public && "called for public access!"); + const Sema::AccessedEntity &Entity) { + assert(Entity.getAccess() != AS_public && "called for public access!"); - // Find a non-anonymous naming class. For records with access, - // there should always be one of these. - CXXRecordDecl *NamingClass = Entity.getNamingClass(); - while (NamingClass->isAnonymousStructOrUnion()) - NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); + switch (IsAccessible(S, EC, Entity)) { + case Sema::AR_dependent: + DelayAccess(S, EC, Loc, Entity); + return Sema::AR_dependent; - // White-list accesses from classes with privileges equivalent to the - // naming class --- but only if the access path isn't forbidden - // (i.e. an access of a private member from a subclass). - if (Access != AS_none && EC.includesClass(NamingClass)) - return Sema::AR_accessible; + case Sema::AR_delayed: + llvm_unreachable("IsAccessible cannot contextually delay"); - // Try to elevate access. - // FIXME: delay if elevation was dependent? - // TODO: on some code, it might be better to do the protected check - // without trying to elevate first. - TryElevateAccess(S, EC, Entity, Access); - if (Access == AS_public) return Sema::AR_accessible; + case Sema::AR_inaccessible: + if (!Entity.isQuiet()) + DiagnoseBadAccess(S, Loc, EC, Entity); + return Sema::AR_inaccessible; - // Protected access. - if (Access == AS_protected) { - // FIXME: implement [class.protected]p1 - for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator - I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) - if ((*I)->isDerivedFrom(NamingClass)) - return Sema::AR_accessible; + case Sema::AR_accessible: + break; + } - // FIXME: delay if we can't decide class derivation yet. + // We only consider the natural access of the declaration when + // deciding whether to do the protected check. + if (Entity.isMemberAccess() && Entity.getAccess() == AS_protected) { + NamedDecl *D = Entity.getTargetDecl(); + if (isa<FieldDecl>(D) || + (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())) { + // FIXME: implement [class.protected] + } } - // Okay, that's it, reject it. - if (!Entity.isQuiet()) - DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); - return Sema::AR_inaccessible; + return Sema::AR_accessible; } static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, @@ -526,6 +838,37 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { DD.Triggered = true; } +void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, + const MultiLevelTemplateArgumentList &TemplateArgs) { + SourceLocation Loc = DD.getAccessLoc(); + AccessSpecifier Access = DD.getAccess(); + + Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(), + TemplateArgs); + if (!NamingD) return; + Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(), + TemplateArgs); + if (!TargetD) return; + + if (DD.isAccessToMember()) { + AccessedEntity Entity(Context, + AccessedEntity::Member, + cast<CXXRecordDecl>(NamingD), + Access, + cast<NamedDecl>(TargetD)); + Entity.setDiag(DD.getDiagnostic()); + CheckAccess(*this, Loc, Entity); + } else { + AccessedEntity Entity(Context, + AccessedEntity::Base, + cast<CXXRecordDecl>(TargetD), + cast<CXXRecordDecl>(NamingD), + Access); + Entity.setDiag(DD.getDiagnostic()); + CheckAccess(*this, Loc, Entity); + } +} + Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, DeclAccessPair Found) { if (!getLangOptions().AccessControl || @@ -533,7 +876,8 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found); + AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), + Found); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getNameLoc(), Entity); @@ -547,7 +891,8 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found); + AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), + Found); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getMemberLoc(), Entity); @@ -565,7 +910,7 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, return AR_accessible; CXXRecordDecl *NamingClass = Dtor->getParent(); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, DeclAccessPair::make(Dtor, Access)); Entity.setDiag(PDiag); // TODO: avoid copy @@ -581,7 +926,7 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = Constructor->getParent(); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, DeclAccessPair::make(Constructor, Access)); Entity.setDiag(diag::err_access_ctor); @@ -599,7 +944,7 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, DeclAccessPair::make(Target, Access)); Entity.setDiag(Diag); return CheckAccess(*this, UseLoc, Entity); @@ -616,7 +961,7 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found); + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); Entity.setDiag(diag::err_access) << PlacementRange; @@ -637,7 +982,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, assert(RT && "found member operator but object expr not of record type"); CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found); + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); @@ -645,6 +990,32 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, return CheckAccess(*this, OpLoc, Entity); } +Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, + DeclAccessPair Found) { + if (!getLangOptions().AccessControl || + Found.getAccess() == AS_none || + Found.getAccess() == AS_public) + return AR_accessible; + + OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer(); + NestedNameSpecifier *Qualifier = Ovl->getQualifier(); + assert(Qualifier && "address of overloaded member without qualifier"); + + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(Ovl->getQualifierRange()); + DeclContext *DC = computeDeclContext(SS); + assert(DC && DC->isRecord() && "scope did not resolve to record"); + CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(DC); + + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); + Entity.setDiag(diag::err_access) + << Ovl->getSourceRange(); + + return CheckAccess(*this, Ovl->getNameLoc(), Entity); +} + + /// Checks access for a hierarchy conversion. /// /// \param IsBaseToDerived whether this is a base-to-derived conversion (true) @@ -671,7 +1042,8 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); - AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access); + AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD, + Path.Access); if (DiagID) Entity.setDiag(DiagID) << Derived << Base; @@ -688,7 +1060,7 @@ void Sema::CheckLookupAccess(const LookupResult &R) { for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (I.getAccess() != AS_public) { - AccessedEntity Entity(AccessedEntity::Member, + AccessedEntity Entity(Context, AccessedEntity::Member, R.getNamingClass(), I.getPair()); Entity.setDiag(diag::err_access); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 014cec2..11c8e6d 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -315,7 +315,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, assert(DestPointer && "Reference to void is not possible"); } else if (DestRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, - PDiag(diag::err_bad_dynamic_cast_incomplete) + Self.PDiag(diag::err_bad_dynamic_cast_incomplete) << DestRange)) return; } else { @@ -353,7 +353,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const RecordType *SrcRecord = SrcPointee->getAs<RecordType>(); if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, - PDiag(diag::err_bad_dynamic_cast_incomplete) + Self.PDiag(diag::err_bad_dynamic_cast_incomplete) << SrcExpr->getSourceRange())) return; } else { @@ -621,8 +621,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_Failed; } - // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation - // than nothing. + // FIXME: We should probably have an AST node for lvalue-to-rvalue + // conversions. return TC_Success; } @@ -698,8 +698,8 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, QualType OrigDestType, unsigned &msg, CastExpr::CastKind &Kind) { // We can only work with complete types. But don't complain if it doesn't work - if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, PDiag(0)) || - Self.RequireCompleteType(OpRange.getBegin(), DestType, PDiag(0))) + if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) || + Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0))) return TC_NotApplicable; // Downcast can only happen in class hierarchies, so we need classes. @@ -808,8 +808,10 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, return TC_NotApplicable; bool WasOverloadedFunction = false; + DeclAccessPair FoundOverload; if (FunctionDecl *Fn - = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false)) { + = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false, + FoundOverload)) { CXXMethodDecl *M = cast<CXXMethodDecl>(Fn); SrcType = Self.Context.getMemberPointerType(Fn->getType(), Self.Context.getTypeDeclType(M->getParent()).getTypePtr()); @@ -870,13 +872,14 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, // allowing complaints if something goes wrong. FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, - true); + true, + FoundOverload); if (!Fn) { msg = 0; return TC_Failed; } - SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, Fn); + SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn); if (!SrcExpr) { msg = 0; return TC_Failed; @@ -913,27 +916,24 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // At this point of CheckStaticCast, if the destination is a reference, // this has to work. There is no other way that works. // On the other hand, if we're checking a C-style cast, we've still got - // the reinterpret_cast way. So in C-style mode, we first try the call - // with an ICS to suppress errors. - if (CStyle) { - ImplicitConversionSequence ICS; - if(Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, /*ForceRValue=*/false, - &ICS)) - return TC_NotApplicable; + // the reinterpret_cast way. + InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); + InitializationKind InitKind = InitializationKind::CreateCast(OpRange, + CStyle); + InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1); + if (InitSeq.getKind() == InitializationSequence::FailedSequence && CStyle) + return TC_NotApplicable; + + Sema::OwningExprResult Result + = InitSeq.Perform(Self, Entity, InitKind, + Action::MultiExprArg(Self, (void**)&SrcExpr, 1)); + if (Result.isInvalid()) { + msg = 0; + return TC_Failed; } - // Now we're committed either way. - if(!Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, 0, - /*IgnoreBaseAccess=*/CStyle)) - return TC_Success; - - // We already got an error message. - msg = 0; - return TC_Failed; + + SrcExpr = Result.takeAs<Expr>(); + return TC_Success; } if (DestType->isRecordType()) { diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 95b79ab..c90f75e 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -486,13 +486,13 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_suggest) << Name << LookupCtx << Found.getLookupName() << SS.getRange() - << CodeModificationHint::CreateReplacement(Found.getNameLoc(), - Found.getLookupName().getAsString()); + << FixItHint::CreateReplacement(Found.getNameLoc(), + Found.getLookupName().getAsString()); else Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest) << Name << Found.getLookupName() - << CodeModificationHint::CreateReplacement(Found.getNameLoc(), - Found.getLookupName().getAsString()); + << FixItHint::CreateReplacement(Found.getNameLoc(), + Found.getLookupName().getAsString()); if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_previous_decl) diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 0a33485..f2520fc 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -184,13 +184,11 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__sync_fetch_and_or: case Builtin::BI__sync_fetch_and_and: case Builtin::BI__sync_fetch_and_xor: - case Builtin::BI__sync_fetch_and_nand: case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_sub_and_fetch: case Builtin::BI__sync_and_and_fetch: case Builtin::BI__sync_or_and_fetch: case Builtin::BI__sync_xor_and_fetch: - case Builtin::BI__sync_nand_and_fetch: case Builtin::BI__sync_val_compare_and_swap: case Builtin::BI__sync_bool_compare_and_swap: case Builtin::BI__sync_lock_test_and_set: @@ -222,11 +220,6 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { if (const FormatAttr *Format = FDecl->getAttr<FormatAttr>()) { if (CheckablePrintfAttr(Format, TheCall)) { bool HasVAListArg = Format->getFirstArg() == 0; - if (!HasVAListArg) { - if (const FunctionProtoType *Proto - = FDecl->getType()->getAs<FunctionProtoType>()) - HasVAListArg = !Proto->isVariadic(); - } CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, HasVAListArg ? 0 : Format->getFirstArg() - 1); } @@ -257,12 +250,6 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { return false; bool HasVAListArg = Format->getFirstArg() == 0; - if (!HasVAListArg) { - const FunctionType *FT = - Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); - if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) - HasVAListArg = !Proto->isVariadic(); - } CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, HasVAListArg ? 0 : Format->getFirstArg() - 1); @@ -315,14 +302,12 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { BUILTIN_ROW(__sync_fetch_and_or), BUILTIN_ROW(__sync_fetch_and_and), BUILTIN_ROW(__sync_fetch_and_xor), - BUILTIN_ROW(__sync_fetch_and_nand), BUILTIN_ROW(__sync_add_and_fetch), BUILTIN_ROW(__sync_sub_and_fetch), BUILTIN_ROW(__sync_and_and_fetch), BUILTIN_ROW(__sync_or_and_fetch), BUILTIN_ROW(__sync_xor_and_fetch), - BUILTIN_ROW(__sync_nand_and_fetch), BUILTIN_ROW(__sync_val_compare_and_swap), BUILTIN_ROW(__sync_bool_compare_and_swap), @@ -357,26 +342,24 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { case Builtin::BI__sync_fetch_and_or: BuiltinIndex = 2; break; case Builtin::BI__sync_fetch_and_and: BuiltinIndex = 3; break; case Builtin::BI__sync_fetch_and_xor: BuiltinIndex = 4; break; - case Builtin::BI__sync_fetch_and_nand:BuiltinIndex = 5; break; - case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 6; break; - case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 7; break; - case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 8; break; - case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 9; break; - case Builtin::BI__sync_xor_and_fetch: BuiltinIndex =10; break; - case Builtin::BI__sync_nand_and_fetch:BuiltinIndex =11; break; + case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 5; break; + case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 6; break; + case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 7; break; + case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 8; break; + case Builtin::BI__sync_xor_and_fetch: BuiltinIndex = 9; break; case Builtin::BI__sync_val_compare_and_swap: - BuiltinIndex = 12; + BuiltinIndex = 10; NumFixed = 2; break; case Builtin::BI__sync_bool_compare_and_swap: - BuiltinIndex = 13; + BuiltinIndex = 11; NumFixed = 2; break; - case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 14; break; + case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 12; break; case Builtin::BI__sync_lock_release: - BuiltinIndex = 15; + BuiltinIndex = 13; NumFixed = 0; break; } @@ -1045,6 +1028,7 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler { Sema &S; const StringLiteral *FExpr; const Expr *OrigFormatExpr; + const unsigned FirstDataArg; const unsigned NumDataArgs; const bool IsObjCLiteral; const char *Beg; // Start of format string. @@ -1056,11 +1040,12 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler { bool atFirstArg; public: CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, - const Expr *origFormatExpr, + const Expr *origFormatExpr, unsigned firstDataArg, unsigned numDataArgs, bool isObjCLiteral, const char *beg, bool hasVAListArg, const CallExpr *theCall, unsigned formatIdx) : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), + FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), IsObjCLiteral(isObjCLiteral), Beg(beg), HasVAListArg(hasVAListArg), @@ -1183,11 +1168,9 @@ void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) { } const Expr *CheckPrintfHandler::getDataArg(unsigned i) const { - return TheCall->getArg(FormatIdx + i + 1); + return TheCall->getArg(FirstDataArg + i); } - - void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS, llvm::StringRef flag, llvm::StringRef cspec, @@ -1329,9 +1312,18 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier return true; if (argIndex >= NumDataArgs) { - S.Diag(getLocationOfByte(CS.getStart()), - diag::warn_printf_insufficient_data_args) - << getFormatSpecifierRange(startSpecifier, specifierLen); + if (FS.usesPositionalArg()) { + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_positional_arg_exceeds_data_args) + << (argIndex+1) << NumDataArgs + << getFormatSpecifierRange(startSpecifier, specifierLen); + } + else { + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_insufficient_data_args) + << getFormatSpecifierRange(startSpecifier, specifierLen); + } + // Don't do any more checking. return false; } @@ -1400,7 +1392,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, return; } - CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, + CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, TheCall->getNumArgs() - firstDataArg, isa<ObjCStringLiteral>(OrigFormatExpr), Str, HasVAListArg, TheCall, format_idx); @@ -2262,10 +2254,6 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { Diag(Param->getLocation(), diag::err_array_star_in_function_definition); } } - - if (getLangOptions().CPlusPlus) - if (const RecordType *RT = Param->getType()->getAs<RecordType>()) - FinalizeVarWithDestructor(Param, RT); } return HasInvalidParm; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e11e161..f3d0dcf 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -14,7 +14,6 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" -#include "AnalysisBasedWarnings.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -89,8 +88,8 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, return 0; // We know from the grammar that this name refers to a type, so build a - // TypenameType node to describe the type. - // FIXME: Record somewhere that this TypenameType node has no "typename" + // DependentNameType node to describe the type. + // FIXME: Record somewhere that this DependentNameType node has no "typename" // keyword associated with it. return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(), II, SS->getRange()).getAsOpaquePtr(); @@ -199,7 +198,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, } else if (UnresolvedUsingTypenameDecl *UUDecl = dyn_cast<UnresolvedUsingTypenameDecl>(IIDecl)) { // FIXME: preserve source structure information. - T = Context.getTypenameType(UUDecl->getTargetNestedNameSpecifier(), &II); + T = Context.getDependentNameType(ETK_None, + UUDecl->getTargetNestedNameSpecifier(), + &II); } else { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); @@ -256,13 +257,13 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, if (!SS || !SS->isSet()) Diag(IILoc, diag::err_unknown_typename_suggest) << &II << Lookup.getLookupName() - << CodeModificationHint::CreateReplacement(SourceRange(IILoc), - Result->getNameAsString()); + << FixItHint::CreateReplacement(SourceRange(IILoc), + Result->getNameAsString()); else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_unknown_nested_typename_suggest) << &II << DC << Lookup.getLookupName() << SS->getRange() - << CodeModificationHint::CreateReplacement(SourceRange(IILoc), - Result->getNameAsString()); + << FixItHint::CreateReplacement(SourceRange(IILoc), + Result->getNameAsString()); else llvm_unreachable("could not have corrected a typo here"); @@ -286,8 +287,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, Diag(SS->getRange().getBegin(), diag::err_typename_missing) << (NestedNameSpecifier *)SS->getScopeRep() << II.getName() << SourceRange(SS->getRange().getBegin(), IILoc) - << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(), - "typename "); + << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename "); SuggestedType = ActOnTypenameType(SourceLocation(), *SS, II, IILoc).get(); } else { assert(SS && SS->isInvalid() && @@ -512,14 +512,30 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { // Types of valid local variables should be complete, so this should succeed. if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { - if (const RecordType *RT = VD->getType()->getAs<RecordType>()) { - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + + // White-list anything with an __attribute__((unused)) type. + QualType Ty = VD->getType(); + + // Only look at the outermost level of typedef. + if (const TypedefType *TT = dyn_cast<TypedefType>(Ty)) { + if (TT->getDecl()->hasAttr<UnusedAttr>()) + return false; + } + + if (const TagType *TT = Ty->getAs<TagType>()) { + const TagDecl *Tag = TT->getDecl(); + if (Tag->hasAttr<UnusedAttr>()) + return false; + + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) { if (!RD->hasTrivialConstructor()) return false; if (!RD->hasTrivialDestructor()) return false; } } + + // TODO: __attribute__((unused)) templates? } return true; @@ -575,8 +591,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) { Diag(RecoverLoc, diag::err_undef_interface_suggest) << Id << IDecl->getDeclName() - << CodeModificationHint::CreateReplacement(RecoverLoc, - IDecl->getNameAsString()); + << FixItHint::CreateReplacement(RecoverLoc, IDecl->getNameAsString()); Diag(IDecl->getLocation(), diag::note_previous_decl) << IDecl->getDeclName(); @@ -982,25 +997,28 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // other tests to run. const FunctionType *OldType = OldQType->getAs<FunctionType>(); const FunctionType *NewType = New->getType()->getAs<FunctionType>(); - if (OldType->getCallConv() != CC_Default && - NewType->getCallConv() == CC_Default) { - NewQType = Context.getCallConvType(NewQType, OldType->getCallConv()); + const FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); + const FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + if (OldTypeInfo.getCC() != CC_Default && + NewTypeInfo.getCC() == CC_Default) { + NewQType = Context.getCallConvType(NewQType, OldTypeInfo.getCC()); New->setType(NewQType); NewQType = Context.getCanonicalType(NewQType); - } else if (!Context.isSameCallConv(OldType->getCallConv(), - NewType->getCallConv())) { + } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), + NewTypeInfo.getCC())) { // Calling conventions really aren't compatible, so complain. Diag(New->getLocation(), diag::err_cconv_change) - << FunctionType::getNameForCallConv(NewType->getCallConv()) - << (OldType->getCallConv() == CC_Default) - << (OldType->getCallConv() == CC_Default ? "" : - FunctionType::getNameForCallConv(OldType->getCallConv())); + << FunctionType::getNameForCallConv(NewTypeInfo.getCC()) + << (OldTypeInfo.getCC() == CC_Default) + << (OldTypeInfo.getCC() == CC_Default ? "" : + FunctionType::getNameForCallConv(OldTypeInfo.getCC())); Diag(Old->getLocation(), diag::note_previous_declaration); return true; } // FIXME: diagnose the other way around? - if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) { + if (OldType->getNoReturnAttr() && + !NewType->getNoReturnAttr()) { NewQType = Context.getNoReturnType(NewQType); New->setType(NewQType); assert(NewQType.isCanonical()); @@ -1094,8 +1112,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { OldProto->isVariadic(), OldProto->getTypeQuals(), false, false, 0, 0, - OldProto->getNoReturnAttr(), - OldProto->getCallConv()); + OldProto->getExtInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); @@ -1176,8 +1193,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { ArgTypes.size(), OldProto->isVariadic(), 0, false, false, 0, 0, - OldProto->getNoReturnAttr(), - OldProto->getCallConv())); + OldProto->getExtInfo())); return MergeCompatibleFunctionDecls(New, Old); } @@ -2132,7 +2148,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, << D.getCXXScopeSpec().getRange(); D.setInvalidType(); // Pretend we didn't see the scope specifier. - DC = 0; + DC = CurContext; + Previous.clear(); } if (getLangOptions().CPlusPlus) { @@ -2328,8 +2345,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (SC == VarDecl::Static) { Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getStorageClassSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } else if (SC == VarDecl::None) SC = VarDecl::Static; } @@ -2405,7 +2421,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Diagnose shadowed variables before filtering for scope. if (!D.getCXXScopeSpec().isSet()) - DiagnoseShadow(S, D, Previous); + CheckShadow(S, NewVD, Previous); // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new @@ -2458,19 +2474,16 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, return NewVD; } -/// \brief Diagnose variable or built-in function shadowing. -/// -/// This method is called as soon as a NamedDecl materializes to check -/// if it shadows another local or global variable, or a built-in function. +/// \brief Diagnose variable or built-in function shadowing. Implements +/// -Wshadow. /// -/// For performance reasons, the lookup results are reused from the calling -/// context. +/// This method is called whenever a VarDecl is added to a "useful" +/// scope. /// /// \param S the scope in which the shadowing name is being declared /// \param R the lookup of the name /// -void Sema::DiagnoseShadow(Scope *S, Declarator &D, - const LookupResult& R) { +void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // Return if warning is ignored. if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored) return; @@ -2524,6 +2537,14 @@ void Sema::DiagnoseShadow(Scope *S, Declarator &D, Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } +/// \brief Check -Wshadow without the advantage of a previous lookup. +void Sema::CheckShadow(Scope *S, VarDecl *D) { + LookupResult R(*this, D->getDeclName(), D->getLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); + LookupName(R, S); + CheckShadow(S, D, R); +} + /// \brief Perform semantic checking on a newly-created variable /// declaration. /// @@ -2913,6 +2934,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } else { // This is a function template specialization. isFunctionTemplateSpecialization = true; + + // C++0x [temp.expl.spec]p20 forbids "template<> 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); + } + + Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) + << Name << RemoveRange + << FixItHint::CreateRemoval(RemoveRange) + << FixItHint::CreateInsertion(InsertLoc, "<>"); + } } // FIXME: Free this memory properly. @@ -2931,8 +2974,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } else if (!CurContext->isRecord()) { // 'virtual' was specified outside of the class. Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getVirtualSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); } else { // Okay: Add virtual to the method. CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC); @@ -2949,16 +2991,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // 'explicit' was specified outside of the class. Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_out_of_class) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getExplicitSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); } else if (!isa<CXXConstructorDecl>(NewFD) && !isa<CXXConversionDecl>(NewFD)) { // 'explicit' was specified on a function that wasn't a constructor // or conversion function. Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_non_ctor_or_conv_function) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getExplicitSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); } } @@ -2971,13 +3011,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, "previously-undeclared friend function being created " "in a non-namespace context"); + // For now, claim that the objects have no previous declaration. if (FunctionTemplate) { - FunctionTemplate->setObjectOfFriendDecl( - /* PreviouslyDeclared= */ !Previous.empty()); + FunctionTemplate->setObjectOfFriendDecl(false); FunctionTemplate->setAccess(AS_public); + } else { + NewFD->setObjectOfFriendDecl(false); } - else - NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ !Previous.empty()); NewFD->setAccess(AS_public); } @@ -2993,8 +3033,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // member function definition. Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getStorageClassSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } // Handle GNU asm-label extension (encoded as an attribute). @@ -3092,18 +3131,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // too few of them). Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) - << CodeModificationHint::CreateInsertion( + << FixItHint::CreateInsertion( D.getDeclSpec().getSourceRange().getBegin(), "template<> "); isFunctionTemplateSpecialization = true; + } else { + // "friend void foo<>(int);" is an implicit specialization decl. + isFunctionTemplateSpecialization = true; } } if (isFunctionTemplateSpecialization) { - if (CheckFunctionTemplateSpecialization(NewFD, - (HasExplicitTemplateArgs ? &TemplateArgs : 0), - Previous)) - NewFD->setInvalidDecl(); + if (isFriend && NewFD->getType()->isDependentType()) { + // FIXME: When we see a friend of a function template + // specialization with a dependent type, we can't match it now; + // for now, we just drop it, until we have a reasonable way to + // represent the parsed-but-not-matched friend function template + // specialization in the AST. + return 0; + } else if (CheckFunctionTemplateSpecialization(NewFD, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), + Previous)) + NewFD->setInvalidDecl(); } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) && CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); @@ -3117,6 +3166,17 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); + if (isFriend && Redeclaration) { + AccessSpecifier Access = NewFD->getPreviousDeclaration()->getAccess(); + if (FunctionTemplate) { + FunctionTemplate->setObjectOfFriendDecl(true); + FunctionTemplate->setAccess(Access); + } else { + NewFD->setObjectOfFriendDecl(true); + } + NewFD->setAccess(Access); + } + // If we have a function template, check the template parameter // list. This will check and merge default template arguments. if (FunctionTemplate) { @@ -3303,7 +3363,8 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // Turn this into a variadic function with no parameters. QualType R = Context.getFunctionType( NewFD->getType()->getAs<FunctionType>()->getResultType(), - 0, 0, true, 0, false, false, 0, 0, false, CC_Default); + 0, 0, true, 0, false, false, 0, 0, + FunctionType::ExtInfo()); NewFD->setType(R); return NewFD->setInvalidDecl(); } @@ -3747,6 +3808,41 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { return; } +/// ActOnInitializerError - Given that there was an error parsing an +/// initializer for the given declaration, try to return to some form +/// of sanity. +void Sema::ActOnInitializerError(DeclPtrTy dcl) { + // Our main concern here is re-establishing invariants like "a + // variable's type is either dependent or complete". + Decl *D = dcl.getAs<Decl>(); + if (!D || D->isInvalidDecl()) return; + + VarDecl *VD = dyn_cast<VarDecl>(D); + if (!VD) return; + + QualType Ty = VD->getType(); + if (Ty->isDependentType()) return; + + // Require a complete type. + if (RequireCompleteType(VD->getLocation(), + Context.getBaseElementType(Ty), + diag::err_typecheck_decl_incomplete_type)) { + VD->setInvalidDecl(); + return; + } + + // Require an abstract type. + if (RequireNonAbstractType(VD->getLocation(), Ty, + diag::err_abstract_type_in_decl, + AbstractVariableType)) { + VD->setInvalidDecl(); + return; + } + + // Don't bother complaining about constructors or destructors, + // though. +} + void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto) { Decl *RealDecl = dcl.getAs<Decl>(); @@ -3984,8 +4080,6 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { II = 0; D.SetIdentifier(0, D.getIdentifierLoc()); D.setInvalidType(true); - } else { - DiagnoseShadow(S, D, R); } } } @@ -4075,7 +4169,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, << ";\n"; Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared) << FTI.ArgInfo[i].Ident - << CodeModificationHint::CreateInsertion(LocAfterDecls, Code.str()); + << FixItHint::CreateInsertion(LocAfterDecls, Code.str()); // Implicitly declare the argument as type 'int' for lack of a better // type. @@ -4213,14 +4307,21 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { // Check the validity of our function parameters CheckParmsForFunctionDef(FD); + bool ShouldCheckShadow = + Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored; + // Introduce our parameters into the function scope for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); Param->setOwningFunction(FD); // If this has an identifier, add it to the scope stack. - if (Param->getIdentifier() && FnBodyScope) + if (Param->getIdentifier() && FnBodyScope) { + if (ShouldCheckShadow) + CheckShadow(FnBodyScope, Param); + PushOnScopeChains(Param, FnBodyScope); + } } // Checking attributes of current function definition @@ -4266,7 +4367,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, else FD = dyn_cast_or_null<FunctionDecl>(dcl); - sema::AnalysisBasedWarnings W(*this); + sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); if (FD) { FD->setBody(Body); @@ -4274,7 +4375,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // C and C++ allow for main to automagically return 0. // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3. FD->setHasImplicitReturnZero(true); - W.disableCheckFallThrough(); + WP.disableCheckFallThrough(); } if (!FD->isInvalidDecl()) @@ -4294,8 +4395,6 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Body->Destroy(Context); return DeclPtrTy(); } - if (!IsInstantiation) - PopDeclContext(); // Verify and clean out per-function state. @@ -4371,12 +4470,15 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, ObjCMethodDecl *MD = cast<ObjCMethodDecl>(dcl); ResultType = MD->getResultType(); } - W.IssueWarnings(dcl); + AnalysisWarnings.IssueWarnings(WP, dcl); } assert(ExprTemporaries.empty() && "Leftover temporaries in function"); } + if (!IsInstantiation) + PopDeclContext(); + PopFunctionOrBlockScope(); // If any errors have occurred, clear out any temporaries that may have @@ -4577,7 +4679,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) << (NewTag == TagDecl::TK_class) << isTemplate << &Name - << CodeModificationHint::CreateReplacement(SourceRange(NewTagLoc), + << FixItHint::CreateReplacement(SourceRange(NewTagLoc), OldTag == TagDecl::TK_class? "class" : "struct"); Diag(Previous->getLocation(), diag::note_previous_use); return true; @@ -4684,7 +4786,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } // A tag 'foo::bar' must already exist. - Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange(); + Diag(NameLoc, diag::err_not_tag_in_scope) + << Kind << Name << DC << SS.getRange(); Name = 0; Invalid = true; goto CreateNewDecl; @@ -4732,6 +4835,79 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + // If we didn't find a previous declaration, and this is a reference + // (or friend reference), move to the correct scope. In C++, we + // also need to do a redeclaration lookup there, just in case + // there's a shadow friend decl. + if (Name && Previous.empty() && + (TUK == TUK_Reference || TUK == TUK_Friend)) { + if (Invalid) goto CreateNewDecl; + assert(SS.isEmpty()); + + if (TUK == TUK_Reference) { + // C++ [basic.scope.pdecl]p5: + // -- for an elaborated-type-specifier of the form + // + // class-key identifier + // + // if the elaborated-type-specifier is used in the + // decl-specifier-seq or parameter-declaration-clause of a + // function defined in namespace scope, the identifier is + // declared as a class-name in the namespace that contains + // the declaration; otherwise, except as a friend + // declaration, the identifier is declared in the smallest + // non-class, non-function-prototype scope that contains the + // declaration. + // + // C99 6.7.2.3p8 has a similar (but not identical!) provision for + // C structs and unions. + // + // It is an error in C++ to declare (rather than define) an enum + // type, including via an elaborated type specifier. We'll + // diagnose that later; for now, declare the enum in the same + // scope as we would have picked for any other tag type. + // + // GNU C also supports this behavior as part of its incomplete + // enum types extension, while GNU C++ does not. + // + // Find the context where we'll be declaring the tag. + // FIXME: We would like to maintain the current DeclContext as the + // lexical context, + while (SearchDC->isRecord()) + SearchDC = SearchDC->getParent(); + + // Find the scope where we'll be declaring the tag. + while (S->isClassScope() || + (getLangOptions().CPlusPlus && + S->isFunctionPrototypeScope()) || + ((S->getFlags() & Scope::DeclScope) == 0) || + (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext())) + S = S->getParent(); + } else { + assert(TUK == TUK_Friend); + // C++ [namespace.memdef]p3: + // If a friend declaration in a non-local class first declares a + // class or function, the friend class or function is a member of + // the innermost enclosing namespace. + SearchDC = SearchDC->getEnclosingNamespaceContext(); + + // Look up through our scopes until we find one with an entity which + // matches our declaration context. + while (S->getEntity() && + ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) { + S = S->getParent(); + assert(S && "No enclosing scope matching the enclosing namespace."); + } + } + + // In C++, look for a shadow friend decl. + if (getLangOptions().CPlusPlus) { + Previous.setRedeclarationKind(ForRedeclaration); + LookupQualifiedName(Previous, SearchDC); + } + } + if (!Previous.empty()) { assert(Previous.isSingleResult()); NamedDecl *PrevDecl = Previous.getFoundDecl(); @@ -4750,8 +4926,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (SafeToContinue) Diag(KWLoc, diag::err_use_with_wrong_tag) << Name - << CodeModificationHint::CreateReplacement(SourceRange(KWLoc), - PrevTagDecl->getKindName()); + << FixItHint::CreateReplacement(SourceRange(KWLoc), + PrevTagDecl->getKindName()); else Diag(KWLoc, diag::err_use_with_wrong_tag) << Name; Diag(PrevTagDecl->getLocation(), diag::note_previous_use); @@ -4829,7 +5005,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } else { // PrevDecl is a namespace, template, or anything else // that lives in the IDNS_Tag identifier namespace. - if (isDeclInScope(PrevDecl, SearchDC, S)) { + if (TUK == TUK_Reference || TUK == TUK_Friend || + isDeclInScope(PrevDecl, SearchDC, S)) { // The tag name clashes with a namespace name, issue an error and // recover by making this tag be anonymous. Diag(NameLoc, diag::err_redefinition_different_kind) << Name; @@ -4843,60 +5020,6 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Previous.clear(); } } - } else if (TUK == TUK_Reference && SS.isEmpty() && Name) { - // C++ [basic.scope.pdecl]p5: - // -- for an elaborated-type-specifier of the form - // - // class-key identifier - // - // if the elaborated-type-specifier is used in the - // decl-specifier-seq or parameter-declaration-clause of a - // function defined in namespace scope, the identifier is - // declared as a class-name in the namespace that contains - // the declaration; otherwise, except as a friend - // declaration, the identifier is declared in the smallest - // non-class, non-function-prototype scope that contains the - // declaration. - // - // C99 6.7.2.3p8 has a similar (but not identical!) provision for - // C structs and unions. - // - // It is an error in C++ to declare (rather than define) an enum - // type, including via an elaborated type specifier. We'll - // diagnose that later; for now, declare the enum in the same - // scope as we would have picked for any other tag type. - // - // GNU C also supports this behavior as part of its incomplete - // enum types extension, while GNU C++ does not. - // - // Find the context where we'll be declaring the tag. - // FIXME: We would like to maintain the current DeclContext as the - // lexical context, - while (SearchDC->isRecord()) - SearchDC = SearchDC->getParent(); - - // Find the scope where we'll be declaring the tag. - while (S->isClassScope() || - (getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) || - ((S->getFlags() & Scope::DeclScope) == 0) || - (S->getEntity() && - ((DeclContext *)S->getEntity())->isTransparentContext())) - S = S->getParent(); - - } else if (TUK == TUK_Friend && SS.isEmpty() && Name) { - // C++ [namespace.memdef]p3: - // If a friend declaration in a non-local class first declares a - // class or function, the friend class or function is a member of - // the innermost enclosing namespace. - SearchDC = SearchDC->getEnclosingNamespaceContext(); - - // Look up through our scopes until we find one with an entity which - // matches our declaration context. - while (S->getEntity() && - ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) { - S = S->getParent(); - assert(S && "No enclosing scope matching the enclosing namespace."); - } } CreateNewDecl: @@ -5013,7 +5136,7 @@ CreateNewDecl: New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty()); // Set the access specifier. - if (!Invalid && TUK != TUK_Friend) + if (!Invalid && SearchDC->isRecord()) SetMemberAccessSpecifier(New, PrevDecl, AS); if (TUK == TUK_Definition) @@ -5026,13 +5149,11 @@ CreateNewDecl: if (PrevDecl) New->setAccess(PrevDecl->getAccess()); - // Friend tag decls are visible in fairly strange ways. - if (!CurContext->isDependentContext()) { - DeclContext *DC = New->getDeclContext()->getLookupContext(); - DC->makeDeclVisibleInContext(New, /* Recoverable = */ false); + DeclContext *DC = New->getDeclContext()->getLookupContext(); + DC->makeDeclVisibleInContext(New, /* Recoverable = */ false); + if (Name) // can be null along some error paths if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false); - } } else if (Name) { S = getNonFieldDeclScope(S); PushOnScopeChains(New, S); @@ -5261,6 +5382,10 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, FieldDecl *NewFD = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL, AS, PrevDecl, &D); + + if (NewFD->isInvalidDecl()) + Record->setInvalidDecl(); + if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something // with the same name in the same scope. @@ -5804,7 +5929,7 @@ void Sema::ActOnFields(Scope* S, } else if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) - Diag(LBrac, diag::err_misplaced_ivar); + Diag(LBrac, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); else { // FIXME. Class extension does not have a LocEnd field. // CDecl->setLocEnd(RBrac); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 73a34f8..cc24735 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -490,6 +490,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, } static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // NOTE: We don't add the attribute to a FunctionDecl because the noreturn + // trait will be part of the function's type. + // Don't apply as a decl attribute to ValueDecl. // FIXME: probably ought to diagnose this. if (isa<ValueDecl>(d)) @@ -521,7 +524,8 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d)) { + if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) && + !isa<TypeDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; @@ -834,18 +838,24 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) return; } - if (!isFunction(D)) { + if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return; } - if (getFunctionType(D)->getResultType()->isVoidType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_void_function) - << Attr.getName(); + if (isFunction(D) && getFunctionType(D)->getResultType()->isVoidType()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) + << Attr.getName() << 0; return; } - + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + if (MD->getResultType()->isVoidType()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) + << Attr.getName() << 1; + return; + } + D->addAttr(::new (S.Context) WarnUnusedResultAttr()); } @@ -1115,6 +1125,7 @@ enum FormatAttrKind { NSStringFormat, StrftimeFormat, SupportedFormat, + IgnoredFormat, InvalidFormat }; @@ -1136,6 +1147,10 @@ static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) { Format == "zcmn_err") return SupportedFormat; + if (Format == "gcc_diag" || Format == "gcc_cdiag" || + Format == "gcc_cxxdiag" || Format == "gcc_tdiag") + return IgnoredFormat; + return InvalidFormat; } @@ -1171,6 +1186,10 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Check for supported formats. FormatAttrKind Kind = getFormatAttrKind(Format); + + if (Kind == IgnoredFormat) + return; + if (Kind == InvalidFormat) { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "format" << Attr.getParameterName()->getName(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 13a7ead..47df435 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1104,8 +1104,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // member. Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) << MemberOrBase << true << R.getLookupName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); Diag(Member->getLocation(), diag::note_previous_decl) << Member->getDeclName(); @@ -1123,8 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // that base class. Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) << MemberOrBase << false << R.getLookupName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec : VirtualBaseSpec; @@ -1429,134 +1429,106 @@ bool Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, - bool IsImplicitConstructor, bool AnyErrors) { + if (Constructor->isDependentContext()) { + // Just store the initializers as written, they will be checked during + // instantiation. + if (NumInitializers > 0) { + Constructor->setNumBaseOrMemberInitializers(NumInitializers); + CXXBaseOrMemberInitializer **baseOrMemberInitializers = + new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; + memcpy(baseOrMemberInitializers, Initializers, + NumInitializers * sizeof(CXXBaseOrMemberInitializer*)); + Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); + } + + return false; + } + // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext()); + CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition(); + if (!ClassDecl) + return true; + llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields; - bool HasDependentBaseInit = false; bool HadError = false; for (unsigned i = 0; i < NumInitializers; i++) { CXXBaseOrMemberInitializer *Member = Initializers[i]; - if (Member->isBaseInitializer()) { - if (Member->getBaseClass()->isDependentType()) - HasDependentBaseInit = true; + + if (Member->isBaseInitializer()) AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member; - } else { + else AllBaseFields[Member->getMember()] = Member; - } } - if (HasDependentBaseInit) { - // FIXME. This does not preserve the ordering of the initializers. - // Try (with -Wreorder) - // template<class X> struct A {}; - // template<class X> struct B : A<X> { - // B() : x1(10), A<X>() {} - // int x1; - // }; - // B<int> x; - // On seeing one dependent type, we should essentially exit this routine - // while preserving user-declared initializer list. When this routine is - // called during instantiatiation process, this routine will rebuild the - // ordered initializer list correctly. - - // If we have a dependent base initialization, we can't determine the - // association between initializers and bases; just dump the known - // initializers into the list, and don't try to deal with other bases. - for (unsigned i = 0; i < NumInitializers; i++) { - CXXBaseOrMemberInitializer *Member = Initializers[i]; - if (Member->isBaseInitializer()) - AllToInit.push_back(Member); - } - } else { - llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit; - - // Push virtual bases before others. - for (CXXRecordDecl::base_class_iterator VBase = - ClassDecl->vbases_begin(), - E = ClassDecl->vbases_end(); VBase != E; ++VBase) { - if (VBase->getType()->isDependentType()) - continue; - if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { - AllToInit.push_back(Value); - } else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, VBase); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { - HadError = true; - continue; - } + llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit; - // Don't attach synthesized base initializers in a dependent - // context; they'll be checked again at template instantiation - // time. - if (CurContext->isDependentContext()) - continue; - - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(VBase->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs<Expr>(), - SourceLocation()); - AllToInit.push_back(CXXBaseInit); - } - } + // Push virtual bases before others. + for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), + E = ClassDecl->vbases_end(); VBase != E; ++VBase) { - for (CXXRecordDecl::base_class_iterator Base = - ClassDecl->bases_begin(), - E = ClassDecl->bases_end(); Base != E; ++Base) { - // Virtuals are in the virtual base list and already constructed. - if (Base->isVirtual()) - continue; - // Skip dependent types. - if (Base->getType()->isDependentType()) + if (CXXBaseOrMemberInitializer *Value + = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { + AllToInit.push_back(Value); + } else if (!AnyErrors) { + InitializedEntity InitEntity + = InitializedEntity::InitializeBase(Context, VBase); + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, + MultiExprArg(*this, 0, 0)); + BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) { + HadError = true; continue; - if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { - AllToInit.push_back(Value); } - else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, Base); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { - HadError = true; - continue; - } - - // Don't attach synthesized base initializers in a dependent - // context; they'll be regenerated at template instantiation - // time. - if (CurContext->isDependentContext()) - continue; - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(Base->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs<Expr>(), - SourceLocation()); - AllToInit.push_back(CXXBaseInit); + CXXBaseOrMemberInitializer *CXXBaseInit = + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(VBase->getType(), + SourceLocation()), + SourceLocation(), + BaseInit.takeAs<Expr>(), + SourceLocation()); + AllToInit.push_back(CXXBaseInit); + } + } + + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); Base != E; ++Base) { + // Virtuals are in the virtual base list and already constructed. + if (Base->isVirtual()) + continue; + + if (CXXBaseOrMemberInitializer *Value + = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { + AllToInit.push_back(Value); + } else if (!AnyErrors) { + InitializedEntity InitEntity + = InitializedEntity::InitializeBase(Context, Base); + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, + MultiExprArg(*this, 0, 0)); + BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) { + HadError = true; + continue; } + + CXXBaseOrMemberInitializer *CXXBaseInit = + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(Base->getType(), + SourceLocation()), + SourceLocation(), + BaseInit.takeAs<Expr>(), + SourceLocation()); + AllToInit.push_back(CXXBaseInit); } } @@ -1624,14 +1596,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, } else if (FT->isReferenceType()) { Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); HadError = true; } else if (FT.isConstQualified()) { Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); HadError = true; @@ -1665,121 +1637,70 @@ static void *GetKeyForTopLevelField(FieldDecl *Field) { return static_cast<void *>(Field); } -static void *GetKeyForBase(QualType BaseType) { - if (const RecordType *RT = BaseType->getAs<RecordType>()) - return (void *)RT; - - assert(0 && "Unexpected base type!"); - return 0; +static void *GetKeyForBase(ASTContext &Context, QualType BaseType) { + return Context.getCanonicalType(BaseType).getTypePtr(); } -static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member, +static void *GetKeyForMember(ASTContext &Context, + CXXBaseOrMemberInitializer *Member, bool MemberMaybeAnon = false) { + if (!Member->isMemberInitializer()) + return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0)); + // For fields injected into the class via declaration of an anonymous union, // use its anonymous union class declaration as the unique key. - if (Member->isMemberInitializer()) { - FieldDecl *Field = Member->getMember(); - - // After SetBaseOrMemberInitializers call, Field is the anonymous union - // data member of the class. Data member used in the initializer list is - // in AnonUnionMember field. - if (MemberMaybeAnon && Field->isAnonymousStructOrUnion()) - Field = Member->getAnonUnionMember(); - if (Field->getDeclContext()->isRecord()) { - RecordDecl *RD = cast<RecordDecl>(Field->getDeclContext()); - if (RD->isAnonymousStructOrUnion()) - return static_cast<void *>(RD); - } - return static_cast<void *>(Field); - } - - return GetKeyForBase(QualType(Member->getBaseClass(), 0)); -} - -/// ActOnMemInitializers - Handle the member initializers for a constructor. -void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, - SourceLocation ColonLoc, - MemInitTy **MemInits, unsigned NumMemInits, - bool AnyErrors) { - if (!ConstructorDecl) - return; + FieldDecl *Field = Member->getMember(); - AdjustDeclIfTemplate(ConstructorDecl); - - CXXConstructorDecl *Constructor - = dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>()); - - if (!Constructor) { - Diag(ColonLoc, diag::err_only_constructors_take_base_inits); - return; - } - - if (!Constructor->isDependentContext()) { - llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members; - bool err = false; - for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = - static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]); - void *KeyToMember = GetKeyForMember(Member); - CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember]; - if (!PrevMember) { - PrevMember = Member; - continue; - } - if (FieldDecl *Field = Member->getMember()) - Diag(Member->getSourceLocation(), - diag::error_multiple_mem_initialization) - << Field->getNameAsString() - << Member->getSourceRange(); - else { - Type *BaseClass = Member->getBaseClass(); - assert(BaseClass && "ActOnMemInitializers - neither field or base"); - Diag(Member->getSourceLocation(), - diag::error_multiple_base_initialization) - << QualType(BaseClass, 0) - << Member->getSourceRange(); - } - Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) - << 0; - err = true; - } - - if (err) - return; - } + // After SetBaseOrMemberInitializers call, Field is the anonymous union + // data member of the class. Data member used in the initializer list is + // in AnonUnionMember field. + if (MemberMaybeAnon && Field->isAnonymousStructOrUnion()) + Field = Member->getAnonUnionMember(); + + // If the field is a member of an anonymous union, we use record decl of the + // union as the key. + RecordDecl *RD = Field->getParent(); + if (RD->isAnonymousStructOrUnion() && RD->isUnion()) + return static_cast<void *>(RD); - SetBaseOrMemberInitializers(Constructor, - reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits), - NumMemInits, false, AnyErrors); + return static_cast<void *>(Field); +} +static void +DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, + const CXXConstructorDecl *Constructor, + CXXBaseOrMemberInitializer **MemInits, + unsigned NumMemInits) { if (Constructor->isDependentContext()) return; - if (Diags.getDiagnosticLevel(diag::warn_base_initialized) == + if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) == Diagnostic::Ignored && - Diags.getDiagnosticLevel(diag::warn_field_initialized) == + SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) == Diagnostic::Ignored) return; - + // Also issue warning if order of ctor-initializer list does not match order // of 1) base class declarations and 2) order of non-static data members. llvm::SmallVector<const void*, 32> AllBaseOrMembers; - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(Constructor->getDeclContext()); + const CXXRecordDecl *ClassDecl = Constructor->getParent(); + // Push virtual bases before others. - for (CXXRecordDecl::base_class_iterator VBase = + for (CXXRecordDecl::base_class_const_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) - AllBaseOrMembers.push_back(GetKeyForBase(VBase->getType())); + AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, + VBase->getType())); - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { // Virtuals are alread in the virtual base list and are constructed // first. if (Base->isVirtual()) continue; - AllBaseOrMembers.push_back(GetKeyForBase(Base->getType())); + AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, + Base->getType())); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -1790,9 +1711,8 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, int curIndex = 0; CXXBaseOrMemberInitializer *PrevMember = 0; for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = - static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]); - void *MemberInCtorList = GetKeyForMember(Member, true); + CXXBaseOrMemberInitializer *Member = MemInits[i]; + void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true); for (; curIndex < Last; curIndex++) if (MemberInCtorList == AllBaseOrMembers[curIndex]) @@ -1804,23 +1724,23 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, if (PrevMember->isBaseInitializer()) { // Diagnostics is for an initialized base class. Type *BaseClass = PrevMember->getBaseClass(); - Diag(PrevMember->getSourceLocation(), - diag::warn_base_initialized) + SemaRef.Diag(PrevMember->getSourceLocation(), + diag::warn_base_initialized) << QualType(BaseClass, 0); } else { FieldDecl *Field = PrevMember->getMember(); - Diag(PrevMember->getSourceLocation(), - diag::warn_field_initialized) + SemaRef.Diag(PrevMember->getSourceLocation(), + diag::warn_field_initialized) << Field->getNameAsString(); } // Also the note! if (FieldDecl *Field = Member->getMember()) - Diag(Member->getSourceLocation(), - diag::note_fieldorbase_initialized_here) << 0 + SemaRef.Diag(Member->getSourceLocation(), + diag::note_fieldorbase_initialized_here) << 0 << Field->getNameAsString(); else { Type *BaseClass = Member->getBaseClass(); - Diag(Member->getSourceLocation(), + SemaRef.Diag(Member->getSourceLocation(), diag::note_fieldorbase_initialized_here) << 1 << QualType(BaseClass, 0); } @@ -1832,6 +1752,64 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, } } +/// ActOnMemInitializers - Handle the member initializers for a constructor. +void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, + SourceLocation ColonLoc, + MemInitTy **meminits, unsigned NumMemInits, + bool AnyErrors) { + if (!ConstructorDecl) + return; + + AdjustDeclIfTemplate(ConstructorDecl); + + CXXConstructorDecl *Constructor + = dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>()); + + if (!Constructor) { + Diag(ColonLoc, diag::err_only_constructors_take_base_inits); + return; + } + + CXXBaseOrMemberInitializer **MemInits = + reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits); + + llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members; + bool HadError = false; + for (unsigned i = 0; i < NumMemInits; i++) { + CXXBaseOrMemberInitializer *Member = MemInits[i]; + + void *KeyToMember = GetKeyForMember(Context, Member); + CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember]; + if (!PrevMember) { + PrevMember = Member; + continue; + } + if (FieldDecl *Field = Member->getMember()) + Diag(Member->getSourceLocation(), + diag::error_multiple_mem_initialization) + << Field->getNameAsString() + << Member->getSourceRange(); + else { + Type *BaseClass = Member->getBaseClass(); + assert(BaseClass && "ActOnMemInitializers - neither field or base"); + Diag(Member->getSourceLocation(), + diag::error_multiple_base_initialization) + << QualType(BaseClass, 0) + << Member->getSourceRange(); + } + Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) + << 0; + HadError = true; + } + + if (HadError) + return; + + DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits); + + SetBaseOrMemberInitializers(Constructor, MemInits, NumMemInits, AnyErrors); +} + void Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, CXXRecordDecl *ClassDecl) { @@ -1861,7 +1839,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context); CheckDestructorAccess(Field->getLocation(), Dtor, - PartialDiagnostic(diag::err_access_dtor_field) + PDiag(diag::err_access_dtor_field) << Field->getDeclName() << FieldType); @@ -1889,7 +1867,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, // FIXME: caret should be on the start of the class name CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor, - PartialDiagnostic(diag::err_access_dtor_base) + PDiag(diag::err_access_dtor_base) << Base->getType() << Base->getSourceRange()); @@ -1914,7 +1892,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); CheckDestructorAccess(ClassDecl->getLocation(), Dtor, - PartialDiagnostic(diag::err_access_dtor_vbase) + PDiag(diag::err_access_dtor_vbase) << VBase->getType()); MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor)); @@ -1925,94 +1903,11 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { if (!CDtorDecl) return; - AdjustDeclIfTemplate(CDtorDecl); - if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>())) - SetBaseOrMemberInitializers(Constructor, 0, 0, false, false); -} - -namespace { - /// PureVirtualMethodCollector - traverses a class and its superclasses - /// and determines if it has any pure virtual methods. - class PureVirtualMethodCollector { - ASTContext &Context; - - public: - typedef llvm::SmallVector<const CXXMethodDecl*, 8> MethodList; - - private: - MethodList Methods; - - void Collect(const CXXRecordDecl* RD, MethodList& Methods); - - public: - PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD) - : Context(Ctx) { - - MethodList List; - Collect(RD, List); - - // Copy the temporary list to methods, and make sure to ignore any - // null entries. - for (size_t i = 0, e = List.size(); i != e; ++i) { - if (List[i]) - Methods.push_back(List[i]); - } - } - - bool empty() const { return Methods.empty(); } - - MethodList::const_iterator methods_begin() { return Methods.begin(); } - MethodList::const_iterator methods_end() { return Methods.end(); } - }; - - void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD, - MethodList& Methods) { - // First, collect the pure virtual methods for the base classes. - for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), - BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) { - if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { - const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (BaseDecl && BaseDecl->isAbstract()) - Collect(BaseDecl, Methods); - } - } - - // Next, zero out any pure virtual methods that this class overrides. - typedef llvm::SmallPtrSet<const CXXMethodDecl*, 4> MethodSetTy; - - MethodSetTy OverriddenMethods; - size_t MethodsSize = Methods.size(); - - for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end(); - i != e; ++i) { - // Traverse the record, looking for methods. - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) { - // If the method is pure virtual, add it to the methods vector. - if (MD->isPure()) - Methods.push_back(MD); - - // Record all the overridden methods in our set. - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - // Keep track of the overridden methods. - OverriddenMethods.insert(*I); - } - } - } - - // Now go through the methods and zero out all the ones we know are - // overridden. - for (size_t i = 0, e = MethodsSize; i != e; ++i) { - if (OverriddenMethods.count(Methods[i])) - Methods[i] = 0; - } - - } + SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false); } - bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, AbstractDiagSelID SelID, const CXXRecordDecl *CurrentRD) { @@ -2066,14 +1961,32 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD)) return true; - PureVirtualMethodCollector Collector(Context, RD); + CXXFinalOverriderMap FinalOverriders; + RD->getFinalOverriders(FinalOverriders); + + for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), + MEnd = FinalOverriders.end(); + M != MEnd; + ++M) { + for (OverridingMethods::iterator SO = M->second.begin(), + SOEnd = M->second.end(); + SO != SOEnd; ++SO) { + // C++ [class.abstract]p4: + // A class is abstract if it contains or inherits at least one + // pure virtual function for which the final overrider is pure + // virtual. + + // + if (SO->second.size() != 1) + continue; - for (PureVirtualMethodCollector::MethodList::const_iterator I = - Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; + if (!SO->second.front().Method->isPure()) + continue; - Diag(MD->getLocation(), diag::note_pure_virtual_function) << - MD->getDeclName(); + Diag(SO->second.front().Method->getLocation(), + diag::note_pure_virtual_function) + << SO->second.front().Method->getDeclName(); + } } if (!PureVirtualClassDiagSet) @@ -2162,22 +2075,79 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I) Convs->setAccess(I, (*I)->getAccess()); - if (!Record->isAbstract()) { - // Collect all the pure virtual methods and see if this is an abstract - // class after all. - PureVirtualMethodCollector Collector(Context, Record); - if (!Collector.empty()) - Record->setAbstract(true); + // Determine whether we need to check for final overriders. We do + // this either when there are virtual base classes (in which case we + // may end up finding multiple final overriders for a given virtual + // function) or any of the base classes is abstract (in which case + // we might detect that this class is abstract). + bool CheckFinalOverriders = false; + if (Record->isPolymorphic() && !Record->isInvalidDecl() && + !Record->isDependentType()) { + if (Record->getNumVBases()) + CheckFinalOverriders = true; + else if (!Record->isAbstract()) { + for (CXXRecordDecl::base_class_const_iterator B = Record->bases_begin(), + BEnd = Record->bases_end(); + B != BEnd; ++B) { + CXXRecordDecl *BaseDecl + = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl()); + if (BaseDecl->isAbstract()) { + CheckFinalOverriders = true; + break; + } + } + } + } + + if (CheckFinalOverriders) { + CXXFinalOverriderMap FinalOverriders; + Record->getFinalOverriders(FinalOverriders); + + for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), + MEnd = FinalOverriders.end(); + M != MEnd; ++M) { + for (OverridingMethods::iterator SO = M->second.begin(), + SOEnd = M->second.end(); + SO != SOEnd; ++SO) { + assert(SO->second.size() > 0 && + "All virtual functions have overridding virtual functions"); + if (SO->second.size() == 1) { + // C++ [class.abstract]p4: + // A class is abstract if it contains or inherits at least one + // pure virtual function for which the final overrider is pure + // virtual. + if (SO->second.front().Method->isPure()) + Record->setAbstract(true); + continue; + } + + // C++ [class.virtual]p2: + // In a derived class, if a virtual member function of a base + // class subobject has more than one final overrider the + // program is ill-formed. + Diag(Record->getLocation(), diag::err_multiple_final_overriders) + << (NamedDecl *)M->first << Record; + Diag(M->first->getLocation(), diag::note_overridden_virtual_function); + for (OverridingMethods::overriding_iterator OM = SO->second.begin(), + OMEnd = SO->second.end(); + OM != OMEnd; ++OM) + Diag(OM->Method->getLocation(), diag::note_final_overrider) + << (NamedDecl *)M->first << OM->Method->getParent(); + + Record->setInvalidDecl(); + } + } } - if (Record->isAbstract()) + if (Record->isAbstract() && !Record->isInvalidDecl()) (void)AbstractClassUsageDiagnoser(*this, Record); } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, - SourceLocation RBrac) { + SourceLocation RBrac, + AttributeList *AttrList) { if (!TagDecl) return; @@ -2185,7 +2155,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, ActOnFields(S, RLoc, TagDecl, (DeclPtrTy*)FieldCollector->getCurFields(), - FieldCollector->getCurNumFields(), LBrac, RBrac, 0); + FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList); CheckCompletedCXXClass( dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>())); @@ -2218,8 +2188,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, /*FIXME*/false, false, - 0, 0, false, - CC_Default), + 0, 0, + FunctionType::ExtInfo()), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, @@ -2293,8 +2263,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { &ArgType, 1, false, 0, /*FIXME:*/false, - false, 0, 0, false, - CC_Default), + false, 0, 0, + FunctionType::ExtInfo()), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, @@ -2382,8 +2352,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Context.getFunctionType(RetType, &ArgType, 1, false, 0, /*FIXME:*/false, - false, 0, 0, false, - CC_Default), + false, 0, 0, + FunctionType::ExtInfo()), /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); @@ -2412,8 +2382,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, /*FIXME:*/false, - false, 0, 0, false, - CC_Default); + false, 0, 0, FunctionType::ExtInfo()); DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); @@ -2586,8 +2555,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, Proto->hasAnyExceptionSpec(), Proto->getNumExceptions(), Proto->exception_begin(), - Proto->getNoReturnAttr(), - Proto->getCallConv()); + Proto->getExtInfo()); } /// CheckConstructor - Checks a fully-formed constructor for @@ -2615,7 +2583,7 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation(); Diag(ParamLoc, diag::err_constructor_byvalue_arg) - << CodeModificationHint::CreateInsertion(ParamLoc, " const &"); + << FixItHint::CreateInsertion(ParamLoc, " const &"); // FIXME: Rather that making the constructor invalid, we should endeavor // to fix the type. @@ -2746,7 +2714,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, // will put in a result type of "int" when none was specified. // FIXME: Exceptions! return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, - false, false, 0, 0, false, CC_Default); + false, false, 0, 0, FunctionType::ExtInfo()); } /// CheckConversionDeclarator - Called by ActOnDeclarator to check the @@ -2822,8 +2790,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, Proto->hasAnyExceptionSpec(), Proto->getNumExceptions(), Proto->exception_begin(), - Proto->getNoReturnAttr(), - Proto->getCallConv()); + Proto->getExtInfo()); // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) @@ -2962,7 +2929,6 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, } else { // Anonymous namespaces. assert(Namespc->isAnonymousNamespace()); - CurContext->addDecl(Namespc); // Link the anonymous namespace into its parent. NamespaceDecl *PrevDecl; @@ -2984,6 +2950,8 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, PrevDecl->setNextNamespace(Namespc); } + CurContext->addDecl(Namespc); + // C++ [namespace.unnamed]p1. An unnamed-namespace-definition // behaves as if it were replaced by // namespace unique { /* empty body */ } @@ -3160,8 +3128,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, UsingLoc = Name.getSourceRange().getBegin(); Diag(UsingLoc, diag::warn_access_decl_deprecated) - << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(), - "using "); + << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using "); } NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, @@ -3330,6 +3297,11 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, CurContext->addDecl(Shadow); Shadow->setAccess(UD->getAccess()); + // Register it as a conversion if appropriate. + if (Shadow->getDeclName().getNameKind() + == DeclarationName::CXXConversionFunctionName) + cast<CXXRecordDecl>(CurContext)->addConversionFunction(Shadow); + if (Orig->isInvalidDecl() || UD->isInvalidDecl()) Shadow->setInvalidDecl(); @@ -3364,6 +3336,10 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, /// decl structures are (very reasonably) not designed for removal. /// (2) avoids this but is very fiddly and phase-dependent. void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { + if (Shadow->getDeclName().getNameKind() == + DeclarationName::CXXConversionFunctionName) + cast<CXXRecordDecl>(Shadow->getDeclContext())->removeConversion(Shadow); + // Remove it from the DeclContext... Shadow->getDeclContext()->removeDecl(Shadow); @@ -3377,7 +3353,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { Shadow->getUsingDecl()->removeShadowDecl(Shadow); // TODO: complain somehow if Shadow was used. It shouldn't - // be possible for this to happen, because + // be possible for this to happen, because...? } /// Builds a using declaration. @@ -3738,8 +3714,10 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) { // We already have an alias with the same name that points to the same // namespace, so don't create a new one. + // FIXME: At some point, we'll want to create the (redundant) + // declaration to maintain better source information. if (!R.isAmbiguous() && !R.empty() && - AD->getNamespace() == getNamespaceDecl(R.getFoundDecl())) + AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl()))) return DeclPtrTy(); } @@ -3780,7 +3758,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, DeclContext *PreviousContext = CurContext; CurContext = Constructor; - if (SetBaseOrMemberInitializers(Constructor, 0, 0, true, false)) { + if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); @@ -3847,7 +3825,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, BaseClassDecl)) { CheckDirectMemberAccess(Base->getSourceRange().getBegin(), BaseAssignOpMethod, - PartialDiagnostic(diag::err_access_assign_base) + PDiag(diag::err_access_assign_base) << Base->getType()); MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); @@ -3866,7 +3844,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, FieldClassDecl)) { CheckDirectMemberAccess(Field->getLocation(), FieldAssignOpMethod, - PartialDiagnostic(diag::err_access_assign_field) + PDiag(diag::err_access_assign_field) << Field->getDeclName() << Field->getType()); MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); @@ -3948,7 +3926,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, BaseClassDecl->getCopyConstructor(Context, TypeQuals)) { CheckDirectMemberAccess(Base->getSourceRange().getBegin(), BaseCopyCtor, - PartialDiagnostic(diag::err_access_copy_base) + PDiag(diag::err_access_copy_base) << Base->getType()); MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor); @@ -3967,7 +3945,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, FieldClassDecl->getCopyConstructor(Context, TypeQuals)) { CheckDirectMemberAccess(Field->getLocation(), FieldCopyCtor, - PartialDiagnostic(diag::err_access_copy_field) + PDiag(diag::err_access_copy_field) << Field->getDeclName() << Field->getType()); MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor); @@ -4062,7 +4040,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context); MarkDeclarationReferenced(VD->getLocation(), Destructor); CheckDestructorAccess(VD->getLocation(), Destructor, - PartialDiagnostic(diag::err_access_dtor_var) + PDiag(diag::err_access_dtor_var) << VD->getDeclName() << VD->getType()); } @@ -4408,16 +4386,18 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // to resolve the overloaded function. If all goes well, T2 is the // type of the resulting function. if (Context.getCanonicalType(T2) == Context.OverloadTy) { + DeclAccessPair Found; FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, - ICS != 0); + ICS != 0, Found); if (Fn) { // Since we're performing this reference-initialization for // real, update the initializer with the resulting function. if (!ICS) { if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; + return true; - Init = FixOverloadedFunctionReference(Init, Fn); + CheckAddressOfMemberAccess(Init, Found); + Init = FixOverloadedFunctionReference(Init, Found, Fn); } T2 = Fn->getType(); @@ -5378,7 +5358,8 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. Declarator TheDeclarator(DS, Declarator::MemberContext); - QualType T = GetTypeForDeclarator(TheDeclarator, S); + TypeSourceInfo *TSI; + QualType T = GetTypeForDeclarator(TheDeclarator, S, &TSI); if (TheDeclarator.isInvalidType()) return DeclPtrTy(); @@ -5396,7 +5377,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // // FIXME: handle "template <> friend class A<T>;", which // is possibly well-formed? Who even knows? - if (TempParams.size() && !isa<ElaboratedType>(T)) { + if (TempParams.size() && !T->isElaboratedTypeSpecifier()) { Diag(Loc, diag::err_tagless_friend_type_template) << DS.getSourceRange(); return DeclPtrTy(); @@ -5408,7 +5389,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // * The class-key of the elaborated-type-specifier is required. // This is one of the rare places in Clang where it's legitimate to // ask about the "spelling" of the type. - if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) { + if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) { // If we evaluated the type to a record type, suggest putting // a tag in front. if (const RecordType *RT = T->getAs<RecordType>()) { @@ -5420,8 +5401,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, << (unsigned) RD->getTagKind() << T << SourceRange(DS.getFriendSpecLoc()) - << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(), - InsertionText); + << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText); return DeclPtrTy(); }else { Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend) @@ -5443,16 +5423,20 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // deadline. It's also a very silly restriction that seriously // affects inner classes and which nobody else seems to implement; // thus we never diagnose it, not even in -pedantic. + // + // But note that we could warn about it: it's always useless to + // friend one of your own members (it's not, however, worthless to + // friend a member of an arbitrary specialization of your template). Decl *D; if (TempParams.size()) D = FriendTemplateDecl::Create(Context, CurContext, Loc, TempParams.size(), (TemplateParameterList**) TempParams.release(), - T.getTypePtr(), + TSI, DS.getFriendSpecLoc()); else - D = FriendDecl::Create(Context, CurContext, Loc, T.getTypePtr(), + D = FriendDecl::Create(Context, CurContext, Loc, TSI, DS.getFriendSpecLoc()); D->setAccess(AS_public); CurContext->addDecl(D); @@ -5889,7 +5873,7 @@ static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) { break; case TSK_ExplicitInstantiationDeclaration: - return true; //FIXME: This looks wrong. + return false; case TSK_ExplicitInstantiationDefinition: // This is method of a explicit instantiation; mark all of the virtual @@ -5945,7 +5929,8 @@ bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() { return true; } -void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) { +void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, + const CXXRecordDecl *RD) { for (CXXRecordDecl::method_iterator i = RD->method_begin(), e = RD->method_end(); i != e; ++i) { CXXMethodDecl *MD = *i; @@ -5955,4 +5940,19 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) { if (MD->isVirtual() && !MD->isPure()) MarkDeclarationReferenced(Loc, MD); } + + // Only classes that have virtual bases need a VTT. + if (RD->getNumVBases() == 0) + return; + + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (i->isVirtual()) + continue; + if (Base->getNumVBases() == 0) + continue; + MarkVirtualMembersReferenced(Loc, Base); + } } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index b2f6717..9bc0846 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -559,8 +559,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( << ClassName << R.getLookupName(); Diag(IDecl->getLocation(), diag::note_previous_decl) << R.getLookupName() - << CodeModificationHint::CreateReplacement(ClassLoc, - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(ClassLoc, + R.getLookupName().getAsString()); IDecl = 0; } else { Diag(ClassLoc, diag::warn_undef_interface) << ClassName; @@ -667,8 +667,6 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, Diag(ClsIvar->getLocation(), diag::note_previous_definition); continue; } - if (ImplIvar->getAccessControl() != ObjCIvarDecl::Private) - Diag(ImplIvar->getLocation(), diag::err_non_private_ivar_declaration); // Instance ivar to Implementation's DeclContext. ImplIvar->setLexicalDeclContext(ImpDecl); IDecl->makeDeclVisibleInContext(ImplIvar, false); @@ -721,12 +719,13 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, } void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, - bool &IncompleteImpl) { + bool &IncompleteImpl, unsigned DiagID) { if (!IncompleteImpl) { Diag(ImpLoc, diag::warn_incomplete_impl); IncompleteImpl = true; } - Diag(ImpLoc, diag::warn_undef_method_impl) << method->getDeclName(); + Diag(method->getLocation(), DiagID) + << method->getDeclName(); } void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, @@ -770,7 +769,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, bool& IncompleteImpl, const llvm::DenseSet<Selector> &InsMap, const llvm::DenseSet<Selector> &ClsMap, - ObjCInterfaceDecl *IDecl) { + ObjCContainerDecl *CDecl) { + ObjCInterfaceDecl *IDecl; + if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) + IDecl = C->getClassInterface(); + else + IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl); + assert (IDecl && "CheckProtocolMethodDefs - IDecl is null"); + ObjCInterfaceDecl *Super = IDecl->getSuperClass(); ObjCInterfaceDecl *NSIDecl = 0; if (getLangOptions().NeXTRuntime) { @@ -808,8 +814,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, // uses the protocol. ObjCMethodDecl *MethodInClass = IDecl->lookupInstanceMethod(method->getSelector()); - if (!MethodInClass || !MethodInClass->isSynthesized()) - WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); + if (!MethodInClass || !MethodInClass->isSynthesized()) { + unsigned DIAG = diag::warn_unimplemented_protocol_method; + if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) { + WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); + Diag(CDecl->getLocation(), diag::note_required_for_protocol_at) + << PDecl->getDeclName(); + } + } } } // check unimplemented class methods @@ -819,8 +831,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, ObjCMethodDecl *method = *I; if (method->getImplementationControl() != ObjCMethodDecl::Optional && !ClsMap.count(method->getSelector()) && - (!Super || !Super->lookupClassMethod(method->getSelector()))) - WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); + (!Super || !Super->lookupClassMethod(method->getSelector()))) { + unsigned DIAG = diag::warn_unimplemented_protocol_method; + if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) { + WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); + Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) << + PDecl->getDeclName(); + } + } } // Check on this protocols's referenced protocols, recursively. for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), @@ -849,7 +867,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, if (!(*I)->isSynthesized() && !InsMap.count((*I)->getSelector())) { if (ImmediateClass) - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl, + diag::note_undef_method_impl); continue; } else { ObjCMethodDecl *ImpMethodDecl = @@ -873,7 +892,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, ClsMapSeen.insert((*I)->getSelector()); if (!ClsMap.count((*I)->getSelector())) { if (ImmediateClass) - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl, + diag::note_undef_method_impl); } else { ObjCMethodDecl *ImpMethodDecl = IMPDecl->getClassMethod((*I)->getSelector()); @@ -950,7 +970,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, - InsMap, ClsMap, C->getClassInterface()); + InsMap, ClsMap, CDecl); // Report unimplemented properties in the category as well. // When reporting on missing setter/getters, do not report when // setter/getter is implemented in category's primary class diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 4ce1ce9..53e9385 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -15,6 +15,8 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallPtrSet.h" @@ -94,19 +96,21 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { } bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { + bool MissingExceptionSpecification = false; bool MissingEmptyExceptionSpecification = false; - if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, - diag::note_previous_declaration, + if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec), + PDiag(diag::note_previous_declaration), Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), New->getType()->getAs<FunctionProtoType>(), New->getLocation(), + &MissingExceptionSpecification, &MissingEmptyExceptionSpecification)) return false; // The failure was something other than an empty exception // specification; return an error. - if (!MissingEmptyExceptionSpecification) + if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification) return true; // The new function declaration is only missing an empty exception @@ -117,8 +121,10 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // to many libc functions as an optimization. Unfortunately, that // optimization isn't permitted by the C++ standard, so we're forced // to work around it here. - if (isa<FunctionProtoType>(New->getType()) && - Context.getSourceManager().isInSystemHeader(Old->getLocation()) && + if (MissingEmptyExceptionSpecification && + isa<FunctionProtoType>(New->getType()) && + (Old->getLocation().isInvalid() || + Context.getSourceManager().isInSystemHeader(Old->getLocation())) && Old->isExternC()) { const FunctionProtoType *NewProto = cast<FunctionProtoType>(New->getType()); @@ -128,12 +134,91 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { NewProto->isVariadic(), NewProto->getTypeQuals(), true, false, 0, 0, - NewProto->getNoReturnAttr(), - NewProto->getCallConv()); + NewProto->getExtInfo()); New->setType(NewType); return false; } + if (MissingExceptionSpecification && isa<FunctionProtoType>(New->getType())) { + const FunctionProtoType *NewProto + = cast<FunctionProtoType>(New->getType()); + const FunctionProtoType *OldProto + = Old->getType()->getAs<FunctionProtoType>(); + + // Update the type of the function with the appropriate exception + // specification. + QualType NewType = Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + NewProto->isVariadic(), + NewProto->getTypeQuals(), + OldProto->hasExceptionSpec(), + OldProto->hasAnyExceptionSpec(), + OldProto->getNumExceptions(), + OldProto->exception_begin(), + NewProto->getExtInfo()); + New->setType(NewType); + + // If exceptions are disabled, suppress the warning about missing + // exception specifications for new and delete operators. + if (!getLangOptions().Exceptions) { + switch (New->getDeclName().getCXXOverloadedOperator()) { + case OO_New: + case OO_Array_New: + case OO_Delete: + case OO_Array_Delete: + if (New->getDeclContext()->isTranslationUnit()) + return false; + break; + + default: + break; + } + } + + // 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); + } + OS << ")"; + OS.flush(); + + SourceLocation AfterParenLoc; + if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { + TypeLoc TL = TSInfo->getTypeLoc(); + if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL)) + AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc()); + } + + if (AfterParenLoc.isInvalid()) + Diag(New->getLocation(), diag::warn_missing_exception_specification) + << New << OS.str(); + else { + // FIXME: This will get more complicated with C++0x + // late-specified return types. + Diag(New->getLocation(), diag::warn_missing_exception_specification) + << New << OS.str() + << FixItHint::CreateInsertion(AfterParenLoc, " " + OS.str().str()); + } + + if (!Old->getLocation().isInvalid()) + Diag(Old->getLocation(), diag::note_previous_declaration); + + return false; + } + Diag(New->getLocation(), diag::err_mismatched_exception_spec); Diag(Old->getLocation(), diag::note_previous_declaration); return true; @@ -146,8 +231,9 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { bool Sema::CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc) { - return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, - diag::note_previous_declaration, + return CheckEquivalentExceptionSpec( + PDiag(diag::err_mismatched_exception_spec), + PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc); } @@ -155,11 +241,17 @@ bool Sema::CheckEquivalentExceptionSpec( /// 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, const PartialDiagnostic & NoteID, - const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc, - bool *MissingEmptyExceptionSpecification) { +bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, + const PartialDiagnostic & NoteID, + const FunctionProtoType *Old, + SourceLocation OldLoc, + const FunctionProtoType *New, + SourceLocation NewLoc, + bool *MissingExceptionSpecification, + bool *MissingEmptyExceptionSpecification) { + if (MissingExceptionSpecification) + *MissingExceptionSpecification = false; + if (MissingEmptyExceptionSpecification) *MissingEmptyExceptionSpecification = false; @@ -168,13 +260,20 @@ bool Sema::CheckEquivalentExceptionSpec( if (OldAny && NewAny) return false; if (OldAny || NewAny) { - if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() && - !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 && + if (MissingExceptionSpecification && Old->hasExceptionSpec() && !New->hasExceptionSpec()) { - // The old type has a throw() exception specification and the - // new type has no exception specification, and the caller asked - // to handle this itself. - *MissingEmptyExceptionSpecification = true; + // 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 + // to handle this itself. + *MissingEmptyExceptionSpecification = true; + } + return true; } @@ -350,7 +449,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, const FunctionProtoType *Source, SourceLocation SourceLoc) { if (CheckSpecForTypesEquivalent(*this, - PDiag(diag::err_deep_exception_specs_differ) << 0, 0, + PDiag(diag::err_deep_exception_specs_differ) << 0, + PDiag(), Target->getResultType(), TargetLoc, Source->getResultType(), SourceLoc)) return true; @@ -361,7 +461,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, "Functions have different argument counts."); for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) { if (CheckSpecForTypesEquivalent(*this, - PDiag(diag::err_deep_exception_specs_differ) << 1, 0, + PDiag(diag::err_deep_exception_specs_differ) << 1, + PDiag(), Target->getArgType(i), TargetLoc, Source->getArgType(i), SourceLoc)) return true; @@ -386,15 +487,16 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) // This means that the source of the conversion can only throw a subset of // the exceptions of the target, and any exception specs on arguments or // return types must be equivalent. - return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs, - 0, ToFunc, From->getSourceRange().getBegin(), + return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), + PDiag(), ToFunc, + From->getSourceRange().getBegin(), FromFunc, SourceLocation()); } bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - return CheckExceptionSpecSubset(diag::err_override_exception_spec, - diag::note_overridden_virtual_function, + return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec), + PDiag(diag::note_overridden_virtual_function), Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), New->getType()->getAs<FunctionProtoType>(), diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index fe6f3b9..fbdf080 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -635,7 +635,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, MemberType = Context.getQualifiedType(MemberType, NewQuals); MarkDeclarationReferenced(Loc, *FI); - PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI); + PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI, *FI); // FIXME: Might this end up being a qualified name? Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, OpLoc, MemberType); @@ -949,8 +949,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, // Actually quite difficult! if (isInstance) Diag(R.getNameLoc(), diagnostic) << Name - << CodeModificationHint::CreateInsertion(R.getNameLoc(), - "this->"); + << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); else Diag(R.getNameLoc(), diagnostic) << Name; @@ -969,14 +968,14 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) { if (SS.isEmpty()) Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); else Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << R.getLookupName() << SS.getRange() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); @@ -1355,10 +1354,27 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, return Owned((Expr*) 0); } -/// \brief Cast member's object to its own class if necessary. +/// \brief Cast a base object to a member's actual type. +/// +/// Logically this happens in three phases: +/// +/// * First we cast from the base type to the naming class. +/// The naming class is the class into which we were looking +/// when we found the member; it's the qualifier type if a +/// qualifier was provided, and otherwise it's the base type. +/// +/// * Next we cast from the naming class to the declaring class. +/// If the member we found was brought into a class's scope by +/// a using declaration, this is that class; otherwise it's +/// the class declaring the member. +/// +/// * 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, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, NamedDecl *Member) { CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext()); if (!RD) @@ -1406,6 +1422,9 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) return false; + SourceRange FromRange = From->getSourceRange(); + SourceLocation FromLoc = FromRange.getBegin(); + // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its // class name. @@ -1424,51 +1443,87 @@ Sema::PerformObjectMemberConversion(Expr *&From, // x = 17; // error: ambiguous base subobjects // Derived1::x = 17; // okay, pick the Base subobject of Derived1 // } - QualType IntermediateRecordType; - QualType IntermediateType; if (Qualifier) { - if (const RecordType *IntermediateRecord - = Qualifier->getAsType()->getAs<RecordType>()) { - IntermediateRecordType = QualType(IntermediateRecord, 0); - IntermediateType = IntermediateRecordType; + QualType QType = QualType(Qualifier->getAsType(), 0); + assert(!QType.isNull() && "lookup done with dependent qualifier?"); + assert(QType->isRecordType() && "lookup done with non-record type"); + + QualType QRecordType = QualType(QType->getAs<RecordType>(), 0); + + // In C++98, the qualifier type doesn't actually have to be a base + // type of the object type, in which case we just ignore it. + // Otherwise build the appropriate casts. + if (IsDerivedFrom(FromRecordType, QRecordType)) { + if (CheckDerivedToBaseConversion(FromRecordType, QRecordType, + FromLoc, FromRange)) + return true; + if (PointerConversions) - IntermediateType = Context.getPointerType(IntermediateType); + QType = Context.getPointerType(QType); + ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue*/ !PointerConversions); + + FromType = QType; + FromRecordType = QRecordType; + + // If the qualifier type was the same as the destination type, + // we're done. + if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) + return false; } } - if (!IntermediateType.isNull() && - IsDerivedFrom(FromRecordType, IntermediateRecordType) && - IsDerivedFrom(IntermediateRecordType, DestRecordType)) { - if (CheckDerivedToBaseConversion(FromRecordType, IntermediateRecordType, - From->getSourceRange().getBegin(), - From->getSourceRange()) || - CheckDerivedToBaseConversion(IntermediateRecordType, DestRecordType, - From->getSourceRange().getBegin(), - From->getSourceRange())) - return true; + bool IgnoreAccess = false; - ImpCastExprToType(From, IntermediateType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/!PointerConversions); - ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/!PointerConversions); - return false; + // If we actually found the member through a using declaration, cast + // down to the using declaration's type. + // + // Pointer equality is fine here because only one declaration of a + // class ever has member declarations. + if (FoundDecl->getDeclContext() != Member->getDeclContext()) { + assert(isa<UsingShadowDecl>(FoundDecl)); + QualType URecordType = Context.getTypeDeclType( + cast<CXXRecordDecl>(FoundDecl->getDeclContext())); + + // We only need to do this if the naming-class to declaring-class + // conversion is non-trivial. + if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) { + assert(IsDerivedFrom(FromRecordType, URecordType)); + if (CheckDerivedToBaseConversion(FromRecordType, URecordType, + FromLoc, FromRange)) + return true; + + QualType UType = URecordType; + if (PointerConversions) + UType = Context.getPointerType(UType); + ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue*/ !PointerConversions); + FromType = UType; + FromRecordType = URecordType; + } + + // We don't do access control for the conversion from the + // declaring class to the true declaring class. + IgnoreAccess = true; } if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, - From->getSourceRange().getBegin(), - From->getSourceRange())) + FromLoc, + FromRange, + IgnoreAccess)) return true; - ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/true); + ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue=*/ !PointerConversions); return false; } /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, const CXXScopeSpec &SS, ValueDecl *Member, - SourceLocation Loc, QualType Ty, + NamedDecl *FoundDecl, SourceLocation Loc, + QualType Ty, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; @@ -1478,7 +1533,7 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, } return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange, - Member, Loc, TemplateArgs, Ty); + Member, FoundDecl, Loc, TemplateArgs, Ty); } /// Builds an implicit member access expression. The current context @@ -2520,7 +2575,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, SourceLocation OpLoc, const CXXScopeSpec &SS) { RecordDecl *RDecl = RTy->getDecl(); if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), - PDiag(diag::err_typecheck_incomplete_tag) + SemaRef.PDiag(diag::err_typecheck_incomplete_tag) << BaseRange)) return true; @@ -2558,8 +2613,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) { SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << DC << R.getLookupName() << SS.getRange() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); @@ -2692,6 +2747,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, } assert(R.isSingleResult()); + NamedDecl *FoundDecl = *R.begin(); NamedDecl *MemberDecl = R.getFoundDecl(); // FIXME: diagnose the presence of template arguments now. @@ -2754,30 +2810,30 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, } MarkDeclarationReferenced(MemberLoc, FD); - if (PerformObjectMemberConversion(BaseExpr, Qualifier, FD)) + if (PerformObjectMemberConversion(BaseExpr, Qualifier, FoundDecl, FD)) return ExprError(); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - FD, MemberLoc, MemberType)); + FD, FoundDecl, MemberLoc, MemberType)); } if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, Var); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Var, MemberLoc, + Var, FoundDecl, MemberLoc, Var->getType().getNonReferenceType())); } if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - MemberFn, MemberLoc, + MemberFn, FoundDecl, MemberLoc, MemberFn->getType())); } if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Enum, MemberLoc, Enum->getType())); + Enum, FoundDecl, MemberLoc, Enum->getType())); } Owned(BaseExpr); @@ -2836,7 +2892,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); Diag(Loc, diag::err_member_reference_needs_call) << QualType(Fun, 0) - << CodeModificationHint::CreateInsertion(Loc, "()"); + << FixItHint::CreateInsertion(Loc, "()"); OwningExprResult NewBase = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc, @@ -2955,7 +3011,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // by now. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << BaseType << int(IsArrow) << BaseExpr->getSourceRange() - << CodeModificationHint::CreateReplacement(OpLoc, "."); + << FixItHint::CreateReplacement(OpLoc, "."); IsArrow = false; } else { Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) @@ -2975,7 +3031,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (PT && PT->getPointeeType()->isRecordType()) { Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << BaseType << int(IsArrow) << BaseExpr->getSourceRange() - << CodeModificationHint::CreateReplacement(OpLoc, "->"); + << FixItHint::CreateReplacement(OpLoc, "->"); BaseType = PT->getPointeeType(); IsArrow = true; } @@ -3014,8 +3070,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Diag(R.getNameLoc(), diag::err_typecheck_member_reference_ivar_suggest) << IDecl->getDeclName() << MemberName << IV->getDeclName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - IV->getNameAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + IV->getNameAsString()); Diag(IV->getLocation(), diag::note_previous_decl) << IV->getDeclName(); } @@ -3189,8 +3245,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Res.getAsSingle<ObjCPropertyDecl>()) { Diag(R.getNameLoc(), diag::err_property_not_found_suggest) << MemberName << BaseType << Res.getLookupName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - Res.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + Res.getLookupName().getAsString()); ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); Diag(Property->getLocation(), diag::note_previous_decl) << Property->getDeclName(); @@ -3519,7 +3575,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, if (NumArgs > 0) { // Pseudo-destructor calls should not have any arguments. Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args) - << CodeModificationHint::CreateRemoval( + << FixItHint::CreateRemoval( SourceRange(Args[0]->getLocStart(), Args[NumArgs-1]->getLocEnd())); @@ -4594,13 +4650,15 @@ Sema::AssignConvertType Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { if (lhsType->isObjCBuiltinType()) { // Class is not compatible with ObjC object pointers. - if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType()) + if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType() && + !rhsType->isObjCQualifiedClassType()) return IncompatiblePointer; return Compatible; } if (rhsType->isObjCBuiltinType()) { // Class is not compatible with ObjC object pointers. - if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType()) + if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType() && + !lhsType->isObjCQualifiedClassType()) return IncompatiblePointer; return Compatible; } @@ -5367,12 +5425,10 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, PDiag(diag::warn_stringcompare) << isa<ObjCEncodeExpr>(literalStringStripped) << literalString->getSourceRange() - << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ") - << CodeModificationHint::CreateInsertion(lex->getLocStart(), - "strcmp(") - << CodeModificationHint::CreateInsertion( - PP.getLocForEndOfToken(rex->getLocEnd()), - resultComparison)); + << FixItHint::CreateReplacement(SourceRange(Loc), ", ") + << FixItHint::CreateInsertion(lex->getLocStart(), "strcmp(") + << FixItHint::CreateInsertion(PP.getLocForEndOfToken(rex->getLocEnd()), + resultComparison)); } } @@ -5783,7 +5839,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_IncompleteType: case Expr::MLV_IncompleteVoidType: return S.RequireCompleteType(Loc, E->getType(), - PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue) + S.PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue) << E->getSourceRange()); case Expr::MLV_DuplicateVectorComponents: Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue; @@ -6345,8 +6401,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, static void SuggestParentheses(Sema &Self, SourceLocation Loc, const PartialDiagnostic &PD, SourceRange ParenRange, - const PartialDiagnostic &SecondPD = PartialDiagnostic(0), - SourceRange SecondParenRange = SourceRange()) { + const PartialDiagnostic &SecondPD, + SourceRange SecondParenRange) { SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { // We can't display the parentheses, so just dig the @@ -6356,8 +6412,8 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, } Self.Diag(Loc, PD) - << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") - << CodeModificationHint::CreateInsertion(EndLoc, ")"); + << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); if (!SecondPD.getDiagID()) return; @@ -6371,8 +6427,8 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, } Self.Diag(Loc, SecondPD) - << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(") - << CodeModificationHint::CreateInsertion(EndLoc, ")"); + << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison @@ -6401,20 +6457,20 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, if (BinOp::isComparisonOp(lhsopc)) SuggestParentheses(Self, OpLoc, - PDiag(diag::warn_precedence_bitwise_rel) + Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(lhs->getLocStart(), OpLoc) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), lhs->getSourceRange(), - PDiag(diag::note_precedence_bitwise_first) + 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, - PDiag(diag::warn_precedence_bitwise_rel) + Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(OpLoc, rhs->getLocEnd()) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), rhs->getSourceRange(), - PDiag(diag::note_precedence_bitwise_first) + Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart())); } @@ -6750,7 +6806,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, Res = BuildAnonymousStructUnionMemberReference( OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>(); } else { - PerformObjectMemberConversion(Res, /*Qualifier=*/0, MemberDecl); + PerformObjectMemberConversion(Res, /*Qualifier=*/0, + *R.begin(), MemberDecl); // MemberDecl->getType() doesn't get the right qualifiers, but it // doesn't matter here. Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd, @@ -6849,8 +6906,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { // The parameter list is optional, if there was none, assume (). if (!T->isFunctionType()) - T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0, false, - CC_Default); + T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0, + FunctionType::ExtInfo()); CurBlock->hasPrototype = true; CurBlock->isVariadic = false; @@ -6905,13 +6962,21 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { CurBlock->Params.size()); CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); + + bool ShouldCheckShadow = + Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored; + for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(), E = CurBlock->TheDecl->param_end(); AI != E; ++AI) { (*AI)->setOwningFunction(CurBlock->TheDecl); // If this has an identifier, add it to the scope stack. - if ((*AI)->getIdentifier()) + if ((*AI)->getIdentifier()) { + if (ShouldCheckShadow) + CheckShadow(CurBlock->TheScope, *AI); + PushOnScopeChains(*AI, CurBlock->TheScope); + } } // Check for a valid sentinel attribute on this block. @@ -6967,11 +7032,11 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, QualType BlockTy; if (!BSI->hasPrototype) BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0, - NoReturn, CC_Default); + FunctionType::ExtInfo(NoReturn, 0, CC_Default)); else BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(), BSI->isVariadic, 0, false, false, 0, 0, - NoReturn, CC_Default); + FunctionType::ExtInfo(NoReturn, 0, CC_Default)); // FIXME: Check that return/parameter types are complete/non-abstract DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end()); @@ -7004,8 +7069,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } // Issue any analysis-based warnings. - sema::AnalysisBasedWarnings W(*this); - W.IssueWarnings(BSI->TheDecl, BlockTy); + const sema::AnalysisBasedWarnings::Policy &WP = + AnalysisWarnings.getDefaultPolicy(); + AnalysisWarnings.IssueWarnings(WP, BSI->TheDecl, BlockTy); Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs); @@ -7066,11 +7132,8 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); } -static void -MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, - QualType DstType, - Expr *SrcExpr, - CodeModificationHint &Hint) { +static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, + Expr *SrcExpr, FixItHint &Hint) { if (!SemaRef.getLangOptions().ObjC1) return; @@ -7091,7 +7154,7 @@ MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, if (!SL || SL->isWide()) return; - Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@"); + Hint = FixItHint::CreateInsertion(SL->getLocStart(), "@"); } bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, @@ -7101,7 +7164,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, // Decode the result (notice that AST's are still created for extensions). bool isInvalid = false; unsigned DiagKind; - CodeModificationHint Hint; + FixItHint Hint; switch (ConvTy) { default: assert(0 && "Unknown conversion type"); @@ -7113,7 +7176,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, DiagKind = diag::ext_typecheck_convert_int_pointer; break; case IncompatiblePointer: - MakeObjCStringLiteralCodeModificationHint(*this, DstType, SrcExpr, Hint); + MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint); DiagKind = diag::ext_typecheck_convert_incompatible_pointer; break; case IncompatiblePointerSign: @@ -7480,10 +7543,10 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { Diag(Loc, diagnostic) << E->getSourceRange() - << CodeModificationHint::CreateInsertion(Open, "(") - << CodeModificationHint::CreateInsertion(Close, ")"); + << FixItHint::CreateInsertion(Open, "(") + << FixItHint::CreateInsertion(Close, ")"); Diag(Loc, diag::note_condition_assign_to_comparison) - << CodeModificationHint::CreateReplacement(Loc, "=="); + << FixItHint::CreateReplacement(Loc, "=="); } bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 366089f..501c877 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -948,7 +948,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, = Context.getFunctionType(Context.VoidTy, ArgTypes.data(), ArgTypes.size(), Proto->isVariadic(), - 0, false, false, 0, 0, false, CC_Default); + 0, false, false, 0, 0, + FunctionType::ExtInfo()); } for (LookupResult::iterator D = FoundDelete.begin(), @@ -1062,10 +1063,15 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // Watch out for variadic allocator function. unsigned NumArgsInFnDecl = FnDecl->getNumParams(); for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { - if (PerformCopyInitialization(Args[i], - FnDecl->getParamDecl(i)->getType(), - AA_Passing)) + OwningExprResult Result + = PerformCopyInitialization(InitializedEntity::InitializeParameter( + FnDecl->getParamDecl(i)), + SourceLocation(), + Owned(Args[i]->Retain())); + if (Result.isInvalid()) return true; + + Args[i] = Result.takeAs<Expr>(); } Operator = FnDecl; CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl); @@ -1204,7 +1210,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0, true, false, HasBadAllocExceptionSpec? 1 : 0, - &BadAllocType, false, CC_Default); + &BadAllocType, + FunctionType::ExtInfo()); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, FnType, /*TInfo=*/0, FunctionDecl::None, false, true); @@ -1295,17 +1302,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Type = Ex->getType(); if (const RecordType *Record = Type->getAs<RecordType>()) { - llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions; + llvm::SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions; + CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); - const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); - + const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = I.getDecl(); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + // Skip over templated conversion functions; they aren't considered. - if (isa<FunctionTemplateDecl>(*I)) + if (isa<FunctionTemplateDecl>(D)) continue; - CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I); + CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); QualType ConvType = Conv->getConversionType().getNonReferenceType(); if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) @@ -1315,9 +1326,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (ObjectPtrConversions.size() == 1) { // We have a single conversion to a pointer-to-object type. Perform // that conversion. + // TODO: don't redo the conversion calculation. Operand.release(); - if (!PerformImplicitConversion(Ex, - ObjectPtrConversions.front()->getConversionType(), + if (!PerformImplicitConversion(Ex, + ObjectPtrConversions.front()->getConversionType(), AA_Converting)) { Operand = Owned(Ex); Type = Ex->getType(); @@ -1326,10 +1338,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, else if (ObjectPtrConversions.size() > 1) { Diag(StartLoc, diag::err_ambiguous_delete_operand) << Type << Ex->getSourceRange(); - for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) { - CXXConversionDecl *Conv = ObjectPtrConversions[i]; - NoteOverloadCandidate(Conv); - } + for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) + NoteOverloadCandidate(ObjectPtrConversions[i]); return ExprError(); } } @@ -1643,14 +1653,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Function_To_Pointer: if (Context.getCanonicalType(FromType) == Context.OverloadTy) { - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true); + DeclAccessPair Found; + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, + true, Found); if (!Fn) return true; if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) return true; - From = FixOverloadedFunctionReference(From, Fn); + From = FixOverloadedFunctionReference(From, Found, Fn); FromType = From->getType(); // If there's already an address-of operator in the expression, we have @@ -1846,7 +1858,7 @@ QualType Sema::CheckPointerToMemberOperands( else { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << 1 << LType - << CodeModificationHint::CreateReplacement(SourceRange(Loc), ".*"); + << FixItHint::CreateReplacement(SourceRange(Loc), ".*"); return QualType(); } } @@ -1891,58 +1903,44 @@ QualType Sema::CheckPointerToMemberOperands( return Result; } -/// \brief Get the target type of a standard or user-defined conversion. -static QualType TargetType(const ImplicitConversionSequence &ICS) { - switch (ICS.getKind()) { - case ImplicitConversionSequence::StandardConversion: - return ICS.Standard.getToType(2); - case ImplicitConversionSequence::UserDefinedConversion: - return ICS.UserDefined.After.getToType(2); - case ImplicitConversionSequence::AmbiguousConversion: - return ICS.Ambiguous.getToType(); - - case ImplicitConversionSequence::EllipsisConversion: - case ImplicitConversionSequence::BadConversion: - llvm_unreachable("function not valid for ellipsis or bad conversions"); - } - return QualType(); // silence warnings -} - /// \brief Try to convert a type to another according to C++0x 5.16p3. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, the two operands are attempted to be /// converted to each other. This function does the conversion in one direction. -/// It emits a diagnostic and returns true only if it finds an ambiguous -/// conversion. +/// It returns true if the program is ill-formed and has already been diagnosed +/// as such. static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, SourceLocation QuestionLoc, - ImplicitConversionSequence &ICS) { + bool &HaveConversion, + QualType &ToType) { + HaveConversion = false; + ToType = To->getType(); + + InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), + SourceLocation()); // C++0x 5.16p3 // The process for determining whether an operand expression E1 of type T1 // can be converted to match an operand expression E2 of type T2 is defined // as follows: // -- If E2 is an lvalue: - if (To->isLvalue(Self.Context) == Expr::LV_Valid) { + bool ToIsLvalue = (To->isLvalue(Self.Context) == Expr::LV_Valid); + if (ToIsLvalue) { // E1 can be converted to match E2 if E1 can be implicitly converted to // type "lvalue reference to T2", subject to the constraint that in the // conversion the reference must bind directly to E1. - if (!Self.CheckReferenceInit(From, - Self.Context.getLValueReferenceType(To->getType()), - To->getLocStart(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - &ICS)) - { - assert((ICS.isStandard() || ICS.isUserDefined()) && - "expected a definite conversion"); - bool DirectBinding = - ICS.isStandard() ? ICS.Standard.DirectBinding - : ICS.UserDefined.After.DirectBinding; - if (DirectBinding) - return false; + QualType T = Self.Context.getLValueReferenceType(ToType); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); + + InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + if (InitSeq.isDirectReferenceBinding()) { + ToType = T; + HaveConversion = true; + return false; } + + if (InitSeq.isAmbiguous()) + return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); } // -- If E2 is an rvalue, or if the conversion above cannot be done: @@ -1952,47 +1950,47 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, QualType TTy = To->getType(); const RecordType *FRec = FTy->getAs<RecordType>(); const RecordType *TRec = TTy->getAs<RecordType>(); - bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy); - if (FRec && TRec && (FRec == TRec || - FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { + bool FDerivedFromT = FRec && TRec && FRec != TRec && + Self.IsDerivedFrom(FTy, TTy); + if (FRec && TRec && + (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { // E1 can be converted to match E2 if the class of T2 is the // same type as, or a base class of, the class of T1, and // [cv2 > cv1]. if (FRec == TRec || FDerivedFromT) { if (TTy.isAtLeastAsQualifiedAs(FTy)) { - // Could still fail if there's no copy constructor. - // FIXME: Is this a hard error then, or just a conversion failure? The - // standard doesn't say. - ICS = Self.TryCopyInitialization(From, TTy, - /*SuppressUserConversions=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - } else { - ICS.setBad(BadConversionSequence::bad_qualifiers, From, TTy); - } - } else { - // Can't implicitly convert FTy to a derived class TTy. - // TODO: more specific error for this. - ICS.setBad(BadConversionSequence::no_conversion, From, TTy); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); + InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + if (InitSeq.getKind() != InitializationSequence::FailedSequence) { + HaveConversion = true; + return false; + } + + if (InitSeq.isAmbiguous()) + return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + } } - } else { - // -- Otherwise: E1 can be converted to match E2 if E1 can be - // implicitly converted to the type that expression E2 would have - // if E2 were converted to an rvalue. - // First find the decayed type. - if (TTy->isFunctionType()) - TTy = Self.Context.getPointerType(TTy); - else if (TTy->isArrayType()) - TTy = Self.Context.getArrayDecayedType(TTy); - - // Now try the implicit conversion. - // FIXME: This doesn't detect ambiguities. - ICS = Self.TryImplicitConversion(From, TTy, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); + + return false; } + + // -- Otherwise: E1 can be converted to match E2 if E1 can be + // implicitly converted to the type that expression E2 would have + // if E2 were converted to an rvalue (or the type it has, if E2 is + // an rvalue). + // + // This actually refers very narrowly to the lvalue-to-rvalue conversion, not + // to the array-to-pointer or function-to-pointer conversions. + if (!TTy->getAs<TagType>()) + TTy = TTy.getUnqualifiedType(); + + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); + InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; + ToType = TTy; + if (InitSeq.isAmbiguous()) + return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + return false; } @@ -2041,37 +2039,17 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, /// \brief Perform an "extended" implicit conversion as returned by /// TryClassUnification. -/// -/// TryClassUnification generates ICSs that include reference bindings. -/// PerformImplicitConversion is not suitable for this; it chokes if the -/// second part of a standard conversion is ICK_DerivedToBase. This function -/// handles the reference binding specially. -static bool ConvertForConditional(Sema &Self, Expr *&E, - const ImplicitConversionSequence &ICS) { - if (ICS.isStandard() && ICS.Standard.ReferenceBinding) { - assert(ICS.Standard.DirectBinding && - "TryClassUnification should never generate indirect ref bindings"); - // FIXME: CheckReferenceInit should be able to reuse the ICS instead of - // redoing all the work. - return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( - TargetType(ICS)), - /*FIXME:*/E->getLocStart(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false); - } - if (ICS.isUserDefined() && ICS.UserDefined.After.ReferenceBinding) { - assert(ICS.UserDefined.After.DirectBinding && - "TryClassUnification should never generate indirect ref bindings"); - return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( - TargetType(ICS)), - /*FIXME:*/E->getLocStart(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false); - } - if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, Sema::AA_Converting)) +static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { + InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); + InitializationKind Kind = InitializationKind::CreateCopy(E->getLocStart(), + SourceLocation()); + InitializationSequence InitSeq(Self, Entity, Kind, &E, 1); + Sema::OwningExprResult Result = InitSeq.Perform(Self, Entity, Kind, + Sema::MultiExprArg(Self, (void **)&E, 1)); + if (Result.isInvalid()) return true; + + E = Result.takeAs<Expr>(); return false; } @@ -2139,17 +2117,17 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // Otherwise, if the second and third operand have different types, and // either has (cv) class type, and attempt is made to convert each of those // operands to the other. - if (Context.getCanonicalType(LTy) != Context.getCanonicalType(RTy) && + if (!Context.hasSameType(LTy, RTy) && (LTy->isRecordType() || RTy->isRecordType())) { ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft; // These return true if a single direction is already ambiguous. - if (TryClassUnification(*this, LHS, RHS, QuestionLoc, ICSLeftToRight)) + QualType L2RType, R2LType; + bool HaveL2R, HaveR2L; + if (TryClassUnification(*this, LHS, RHS, QuestionLoc, HaveL2R, L2RType)) return QualType(); - if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft)) + if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType)) return QualType(); - - bool HaveL2R = !ICSLeftToRight.isBad(); - bool HaveR2L = !ICSRightToLeft.isBad(); + // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) @@ -2161,11 +2139,11 @@ 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, ICSLeftToRight)) + if (ConvertForConditional(*this, LHS, L2RType)) return QualType(); LTy = LHS->getType(); } else if (HaveR2L) { - if (ConvertForConditional(*this, RHS, ICSRightToLeft)) + if (ConvertForConditional(*this, RHS, R2LType)) return QualType(); RTy = RHS->getType(); } @@ -2174,7 +2152,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // C++0x 5.16p4 // If the second and third operands are lvalues and have the same type, // the result is of that type [...] - bool Same = Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy); + bool Same = Context.hasSameType(LTy, RTy); if (Same && LHS->isLvalue(Context) == Expr::LV_Valid && RHS->isLvalue(Context) == Expr::LV_Valid) return LTy; @@ -2235,7 +2213,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return Composite; } - // Similarly, attempt to find composite type of twp objective-c pointers. + // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!Composite.isNull()) return Composite; @@ -2611,7 +2589,7 @@ Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc); Diag(E->getLocStart(), diag::err_dtor_expr_without_call) << isa<CXXPseudoDestructorExpr>(E) - << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + << FixItHint::CreateInsertion(ExpectedLParenLoc, "()"); return ActOnCallExpr(/*Scope*/ 0, move(MemExpr), @@ -2645,7 +2623,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, // The user wrote "p->" when she probably meant "p."; fix it. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true - << CodeModificationHint::CreateReplacement(OpLoc, "."); + << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); @@ -2750,7 +2728,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, // The user wrote "p->" when she probably meant "p."; fix it. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true - << CodeModificationHint::CreateReplacement(OpLoc, "."); + << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); @@ -2874,8 +2852,10 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, } CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, + NamedDecl *FoundDecl, CXXMethodDecl *Method) { - if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, Method)) + if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, + FoundDecl, Method)) assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?"); MemberExpr *ME = @@ -2919,7 +2899,8 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); // Create an implicit call expr that calls it. - CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method); + // FIXME: pass the FoundDecl for the user-defined conversion here + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method, Method); return MaybeBindToTemporary(CE); } } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index c98ba43..d5a22ca 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -289,7 +289,10 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( IdentifierInfo *receiverNamePtr = &receiverName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr); - + if (!IFace) { + Diag(receiverNameLoc, diag::err_expected_ident_or_lparen); + return ExprError(); + } // Search for a declared property first. Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index f86ae51..648e43b 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -504,13 +504,11 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), diag::warn_missing_braces) << StructuredSubobjectInitList->getSourceRange() - << CodeModificationHint::CreateInsertion( - StructuredSubobjectInitList->getLocStart(), - "{") - << CodeModificationHint::CreateInsertion( - SemaRef.PP.getLocForEndOfToken( + << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(), + "{") + << FixItHint::CreateInsertion(SemaRef.PP.getLocForEndOfToken( StructuredSubobjectInitList->getLocEnd()), - "}"); + "}"); } } @@ -571,8 +569,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, if (T->isScalarType() && !TopLevelObject) SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init) << IList->getSourceRange() - << CodeModificationHint::CreateRemoval(IList->getLocStart()) - << CodeModificationHint::CreateRemoval(IList->getLocEnd()); + << FixItHint::CreateRemoval(IList->getLocStart()) + << FixItHint::CreateRemoval(IList->getLocEnd()); } void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, @@ -1363,8 +1361,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown_suggest) << FieldName << CurrentObjectType << R.getLookupName() - << CodeModificationHint::CreateReplacement(D->getFieldLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(D->getFieldLoc(), + R.getLookupName().getAsString()); SemaRef.Diag(ReplacementField->getLocation(), diag::note_previous_decl) << ReplacementField->getDeclName(); @@ -2001,14 +1999,48 @@ void InitializationSequence::Step::Destroy() { } } +bool InitializationSequence::isDirectReferenceBinding() const { + return getKind() == ReferenceBinding && Steps.back().Kind == SK_BindReference; +} + +bool InitializationSequence::isAmbiguous() const { + if (getKind() != FailedSequence) + return false; + + switch (getFailureKind()) { + case FK_TooManyInitsForReference: + case FK_ArrayNeedsInitList: + case FK_ArrayNeedsInitListOrStringLiteral: + case FK_AddressOfOverloadFailed: // FIXME: Could do better + case FK_NonConstLValueReferenceBindingToTemporary: + case FK_NonConstLValueReferenceBindingToUnrelated: + case FK_RValueReferenceBindingToLValue: + case FK_ReferenceInitDropsQualifiers: + case FK_ReferenceInitFailed: + case FK_ConversionFailed: + case FK_TooManyInitsForScalar: + case FK_ReferenceBindingToInitList: + case FK_InitListBadDestinationType: + case FK_DefaultInitOfConst: + return false; + + case FK_ReferenceInitOverloadFailed: + case FK_UserConversionOverloadFailed: + case FK_ConstructorOverloadFailed: + return FailedOverloadResult == OR_Ambiguous; + } + + return false; +} + void InitializationSequence::AddAddressOverloadResolutionStep( - FunctionDecl *Function) { + FunctionDecl *Function, + DeclAccessPair Found) { Step S; S.Kind = SK_ResolveAddressOfOverloadedFunction; S.Type = Function->getType(); - // Access is currently ignored for these. S.Function.Function = Function; - S.Function.FoundDecl = DeclAccessPair::make(Function, AS_none); + S.Function.FoundDecl = Found; Steps.push_back(S); } @@ -2341,15 +2373,17 @@ static void TryReferenceInitialization(Sema &S, // to resolve the overloaded function. If all goes well, T2 is the // type of the resulting function. if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { + DeclAccessPair Found; FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, T1, - false); + false, + Found); if (!Fn) { Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); return; } - Sequence.AddAddressOverloadResolutionStep(Fn); + Sequence.AddAddressOverloadResolutionStep(Fn, Found); cv2T2 = Fn->getType(); T2 = cv2T2.getUnqualifiedType(); } @@ -2802,7 +2836,7 @@ static void TryUserDefinedConversion(Sema &S, if (ConvTemplate) Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); else - Conv = cast<CXXConversionDecl>(*I); + Conv = cast<CXXConversionDecl>(D); if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) @@ -3314,8 +3348,9 @@ InitializationSequence::Perform(Sema &S, case SK_ResolveAddressOfOverloadedFunction: // Overload resolution determined which function invoke; update the // initializer to reflect that choice. - // Access control was done in overload resolution. + S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl); CurInit = S.FixOverloadedFunctionReference(move(CurInit), + Step->Function.FoundDecl, Step->Function.Function); break; @@ -3382,6 +3417,7 @@ InitializationSequence::Perform(Sema &S, bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; + bool IsLvalue = false; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); @@ -3414,7 +3450,7 @@ InitializationSequence::Perform(Sema &S, } else { // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); - + IsLvalue = Conversion->getResultType()->isLValueReferenceType(); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, FoundFn); @@ -3422,7 +3458,7 @@ InitializationSequence::Perform(Sema &S, // 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, - Conversion)) + FoundFn, Conversion)) return S.ExprError(); // Do a little dance to make sure that CurInit has the proper @@ -3430,7 +3466,8 @@ InitializationSequence::Perform(Sema &S, CurInit.release(); // Build the actual call to the conversion function. - CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, Conversion)); + CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn, + Conversion)); if (CurInit.isInvalid() || !CurInit.get()) return S.ExprError(); @@ -3444,7 +3481,7 @@ InitializationSequence::Perform(Sema &S, CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), CastKind, CurInitExpr, - false)); + IsLvalue)); if (!IsCopy) CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit)); @@ -3614,11 +3651,14 @@ bool InitializationSequence::Diagnose(Sema &S, << (Failure == FK_ArrayNeedsInitListOrStringLiteral); break; - case FK_AddressOfOverloadFailed: + case FK_AddressOfOverloadFailed: { + DeclAccessPair Found; S.ResolveAddressOfOverloadedFunction(Args[0], DestType.getNonReferenceType(), - true); + true, + Found); break; + } case FK_ReferenceInitOverloadFailed: case FK_UserConversionOverloadFailed: diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 18a0938..7c6327f 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -599,12 +599,20 @@ public: step_iterator step_begin() const { return Steps.begin(); } step_iterator step_end() const { return Steps.end(); } + /// \brief Determine whether this initialization is a direct reference + /// binding (C++ [dcl.init.ref]). + bool isDirectReferenceBinding() const; + + /// \brief Determine whether this initialization failed due to an ambiguity. + bool isAmbiguous() const; + /// \brief Add a new step in the initialization that resolves the address /// of an overloaded function to a specific function declaration. /// /// \param Function the function to which the overloaded function reference /// resolves. - void AddAddressOverloadResolutionStep(FunctionDecl *Function); + void AddAddressOverloadResolutionStep(FunctionDecl *Function, + DeclAccessPair Found); /// \brief Add a new step in the initialization that performs a derived-to- /// base cast. diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 9ae520d..a29c4d4 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -304,6 +304,23 @@ void LookupResult::configure() { SemaRef.getLangOptions().CPlusPlus, isForRedeclaration()); IsAcceptableFn = getResultFilter(LookupKind); + + // If we're looking for one of the allocation or deallocation + // operators, make sure that the implicitly-declared new and delete + // operators can be found. + if (!isForRedeclaration()) { + switch (Name.getCXXOverloadedOperator()) { + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + SemaRef.DeclareGlobalNewDelete(); + break; + + default: + break; + } + } } // Necessary because CXXBasePaths is not complete in Sema.h @@ -539,13 +556,13 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // Compute the type of the function that we would expect the conversion // function to have, if it were to match the name given. // FIXME: Calling convention! + FunctionType::ExtInfo ConvProtoInfo = ConvProto->getExtInfo(); QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), 0, 0, ConvProto->isVariadic(), ConvProto->getTypeQuals(), false, false, 0, 0, - ConvProto->getNoReturnAttr(), - CC_Default); + ConvProtoInfo.withCallingConv(CC_Default)); // Perform template argument deduction against the type that we would // expect the function to have. diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 41ed6c6..f815068 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -44,9 +44,6 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Diag(AtLoc, diag::error_reference_property); return DeclPtrTy(); } - // Validate the attributes on the @property. - CheckObjCPropertyAttributes(T, AtLoc, Attributes); - // Proceed with constructing the ObjCPropertDecls. ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(ClassCategory.getAs<Decl>()); @@ -60,10 +57,13 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, isOverridingProperty, T, MethodImplKind); - return DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD, + DeclPtrTy Res = DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, T, MethodImplKind)); + // Validate the attributes on the @property. + CheckObjCPropertyAttributes(Res, AtLoc, Attributes); + return Res; } Sema::DeclPtrTy @@ -93,6 +93,11 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), PropertyId, AtLoc, T); + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); + if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); + DC->addDecl(PDecl); // We need to look in the @interface to see if the @property was @@ -378,7 +383,9 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, if (PropType != IvarType) { if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { Diag(PropertyLoc, diag::error_property_ivar_type) - << property->getDeclName() << Ivar->getDeclName(); + << property->getDeclName() << PropType + << Ivar->getDeclName() << IvarType; + Diag(Ivar->getLocation(), diag::note_ivar_decl); // Note! I deliberately want it to fall thru so, we have a // a property implementation and to avoid future warnings. } @@ -391,7 +398,9 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, if (lhsType != rhsType && lhsType->isArithmeticType()) { Diag(PropertyLoc, diag::error_property_ivar_type) - << property->getDeclName() << Ivar->getDeclName(); + << property->getDeclName() << PropType + << Ivar->getDeclName() << IvarType; + Diag(Ivar->getLocation(), diag::note_ivar_decl); // Fall thru - see previous comment } // __weak is explicit. So it works on Canonical type. @@ -973,10 +982,13 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, AddInstanceMethodToGlobalPool(SetterMethod); } -void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, +void Sema::CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy, SourceLocation Loc, unsigned &Attributes) { // FIXME: Improve the reported location. + Decl *PDecl = PropertyPtrTy.getAs<Decl>(); + ObjCPropertyDecl *PropertyDecl = dyn_cast_or_null<ObjCPropertyDecl>(PDecl); + QualType PropertyTy = PropertyDecl->getType(); // readonly and readwrite/assign/retain/copy conflict. if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && @@ -1001,7 +1013,8 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && !PropertyTy->isObjCObjectPointerType() && !PropertyTy->isBlockPointerType() && - !Context.isObjCNSObjectType(PropertyTy)) { + !Context.isObjCNSObjectType(PropertyTy) && + !PropertyDecl->getAttr<ObjCNSObjectAttr>()) { Diag(Loc, diag::err_objc_property_requires_object) << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain"); Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 410bf9a..bc10a58 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -567,6 +567,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // array-to-pointer conversion, or function-to-pointer conversion // (C++ 4p1). + DeclAccessPair AccessPair; + // Lvalue-to-rvalue conversion (C++ 4.1): // An lvalue (3.10) of a non-function, non-array type T can be // converted to an rvalue. @@ -612,7 +614,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(From, ToType, false)) { + = ResolveAddressOfOverloadedFunction(From, ToType, false, + AccessPair)) { // Address of overloaded function (C++ [over.over]). SCS.First = ICK_Function_To_Pointer; @@ -1579,10 +1582,10 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, CXXConversionDecl *Conv; FunctionTemplateDecl *ConvTemplate; - if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(*I))) - Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D))) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); else - Conv = dyn_cast<CXXConversionDecl>(*I); + Conv = cast<CXXConversionDecl>(D); if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) @@ -2201,44 +2204,6 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType, } } -/// PerformCopyInitialization - Copy-initialize an object of type @p ToType with -/// the expression @p From. Returns true (and emits a diagnostic) if there was -/// an error, returns false if the initialization succeeded. Elidable should -/// be true when the copy may be elided (C++ 12.8p15). Overload resolution works -/// differently in C++0x for this case. -bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, - AssignmentAction Action, bool Elidable) { - if (!getLangOptions().CPlusPlus) { - // In C, argument passing is the same as performing an assignment. - QualType FromType = From->getType(); - - AssignConvertType ConvTy = - CheckSingleAssignmentConstraints(ToType, From); - if (ConvTy != Compatible && - CheckTransparentUnionArgumentConstraints(ToType, From) == Compatible) - ConvTy = Compatible; - - return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType, - FromType, From, Action); - } - - if (ToType->isReferenceType()) - return CheckReferenceInit(From, ToType, - /*FIXME:*/From->getLocStart(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false); - - if (!PerformImplicitConversion(From, ToType, Action, - /*AllowExplicit=*/false, Elidable)) - return false; - if (!DiagnoseMultipleUserDefinedConversion(From, ToType)) - return Diag(From->getSourceRange().getBegin(), - diag::err_typecheck_convert_incompatible) - << ToType << From->getType() << Action << From->getSourceRange(); - return true; -} - /// TryObjectArgumentInitialization - Try to initialize the object /// parameter of the given member function (@c Method) from the /// expression @p From. @@ -2316,6 +2281,7 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType, bool Sema::PerformObjectArgumentInitialization(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, CXXMethodDecl *Method) { QualType FromRecordType, DestType; QualType ImplicitParamRecordType = @@ -2340,7 +2306,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); if (ICS.Standard.Second == ICK_Derived_To_Base) - return PerformObjectMemberConversion(From, Qualifier, Method); + return PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method); if (!Context.hasSameType(From->getType(), DestType)) ImpCastExprToType(From, DestType, CastExpr::CK_NoOp, @@ -3344,13 +3310,16 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, = ClassDecl->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = I.getDecl(); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); // Skip conversion function templates; they don't tell us anything // about which builtin types we can convert to. - if (isa<FunctionTemplateDecl>(*I)) + if (isa<FunctionTemplateDecl>(D)) continue; - CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I); + CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); if (AllowExplicitConversions || !Conv->isExplicit()) { AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, VisibleQuals); @@ -3412,7 +3381,10 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { - if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) { + NamedDecl *D = I.getDecl(); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D)) { QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); if (const ReferenceType *ResTypeRef = CanTy->getAs<ReferenceType>()) CanTy = ResTypeRef->getPointeeType(); @@ -4733,7 +4705,7 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, if (!ICS.isAmbiguous()) continue; S.DiagnoseAmbiguousConversion(ICS, OpLoc, - PDiag(diag::note_ambiguous_type_conversion)); + S.PDiag(diag::note_ambiguous_type_conversion)); } } @@ -4980,7 +4952,8 @@ static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) { /// routine will emit diagnostics if there is an error. FunctionDecl * Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, - bool Complain) { + bool Complain, + DeclAccessPair &FoundResult) { QualType FunctionType = ToType; bool IsMember = false; if (const PointerType *ToTypePtr = ToType->getAs<PointerType>()) @@ -5018,6 +4991,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // Look through all of the overloaded functions, searching for one // whose type matches exactly. llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches; + llvm::SmallVector<FunctionDecl *, 4> NonMatches; + bool FoundNonTemplateFunction = false; for (UnresolvedSetIterator I = OvlExpr->decls_begin(), E = OvlExpr->decls_end(); I != E; ++I) { @@ -5097,9 +5072,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; else if (Matches.size() == 1) { FunctionDecl *Result = Matches[0].second; + FoundResult = Matches[0].first; MarkDeclarationReferenced(From->getLocStart(), Result); if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); + CheckAddressOfMemberAccess(OvlExpr, Matches[0].first); return Result; } @@ -5131,10 +5107,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, << (unsigned) oc_function_template); assert(Result != MatchesCopy.end() && "no most-specialized template"); MarkDeclarationReferenced(From->getLocStart(), *Result); - if (Complain) { - DeclAccessPair FoundDecl = Matches[Result - MatchesCopy.begin()].first; - CheckUnresolvedAccess(*this, OvlExpr, FoundDecl); - } + FoundResult = Matches[Result - MatchesCopy.begin()].first; + if (Complain) + CheckUnresolvedAccess(*this, OvlExpr, FoundResult); return cast<FunctionDecl>(*Result); } @@ -5153,6 +5128,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // selected function. if (Matches.size() == 1) { MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); + FoundResult = Matches[0].first; if (Complain) CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); return cast<FunctionDecl>(Matches[0].second); @@ -5433,7 +5409,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, case OR_Success: { FunctionDecl *FDecl = Best->Function; CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); - Fn = FixOverloadedFunctionReference(Fn, FDecl); + Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } @@ -5560,7 +5536,8 @@ 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, Method)) + if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, + Best->FoundDecl, Method)) return ExprError(); } else { // Convert the arguments. @@ -5754,7 +5731,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return ExprError(); if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, - Method)) + Best->FoundDecl, Method)) return ExprError(); Args[1] = RHS = Arg1.takeAs<Expr>(); @@ -5921,7 +5898,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, - Method)) + Best->FoundDecl, Method)) return ExprError(); // Convert the arguments. @@ -6026,10 +6003,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, MemberExpr *MemExpr; CXXMethodDecl *Method = 0; + NamedDecl *FoundDecl = 0; NestedNameSpecifier *Qualifier = 0; if (isa<MemberExpr>(NakedMemExpr)) { MemExpr = cast<MemberExpr>(NakedMemExpr); Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl()); + FoundDecl = MemExpr->getFoundDecl(); Qualifier = MemExpr->getQualifier(); } else { UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr); @@ -6079,6 +6058,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { case OR_Success: Method = cast<CXXMethodDecl>(Best->Function); + FoundDecl = Best->FoundDecl; CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); break; @@ -6106,7 +6086,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return ExprError(); } - MemExprE = FixOverloadedFunctionReference(MemExprE, Method); + MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method); // If overload resolution picked a static member, build a // non-member call based on that function. @@ -6131,9 +6111,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return ExprError(); // 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, Method)) + PerformObjectArgumentInitialization(ObjectArg, Qualifier, + FoundDecl, Method)) return ExprError(); MemExpr->setBase(ObjectArg); @@ -6173,7 +6156,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); if (RequireCompleteType(LParenLoc, Object->getType(), - PartialDiagnostic(diag::err_incomplete_object_call) + PDiag(diag::err_incomplete_object_call) << Object->getSourceRange())) return true; @@ -6293,7 +6276,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Create an implicit member expr to refer to the conversion operator. // and then call it. - CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Conv); + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Best->FoundDecl, + Conv); return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc, MultiExprArg(*this, (ExprTy**)Args, NumArgs), @@ -6353,7 +6337,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Initialize the implicit object parameter. IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0, - Method); + Best->FoundDecl, Method); TheCall->setArg(0, Object); @@ -6474,7 +6458,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { // Convert the object parameter. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); - if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, Method)) + if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, + Best->FoundDecl, Method)) return ExprError(); // No concerns about early exits now. @@ -6501,9 +6486,11 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { /// perhaps a '&' around it). We have resolved the overloaded function /// to the function declaration Fn, so patch up the expression E to /// refer (possibly indirectly) to Fn. Returns the new expr. -Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { +Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found, + FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), + Found, Fn); if (SubExpr == PE->getSubExpr()) return PE->Retain(); @@ -6511,7 +6498,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), + Found, Fn); assert(Context.hasSameType(ICE->getSubExpr()->getType(), SubExpr->getType()) && "Implicit cast type cannot be determined from overload"); @@ -6535,7 +6523,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { // Fix the sub expression, which really has to be an // UnresolvedLookupExpr holding an overloaded member function // or template. - Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), + Found, Fn); if (SubExpr == UnOp->getSubExpr()) return UnOp->Retain(); @@ -6556,7 +6545,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { MemPtrType, UnOp->getOperatorLoc()); } } - Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), + Found, Fn); if (SubExpr == UnOp->getSubExpr()) return UnOp->Retain(); @@ -6618,6 +6608,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { MemExpr->getQualifier(), MemExpr->getQualifierRange(), Fn, + Found, MemExpr->getMemberLoc(), TemplateArgs, Fn->getType()); @@ -6628,8 +6619,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E, + NamedDecl *Found, FunctionDecl *Fn) { - return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Fn)); + return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn)); } } // end namespace clang diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index fd65c32..791de8c 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -119,7 +119,13 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } } } - + else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) { + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (MD && MD->getAttr<WarnUnusedResultAttr>()) { + Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; + return; + } + } Diag(Loc, DiagID) << R1 << R2; } @@ -427,48 +433,50 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, // Make sure that the condition expression has a complete type, // otherwise we'll never find any conversions. if (S.RequireCompleteType(SwitchLoc, CondType, - PDiag(diag::err_switch_incomplete_class_type) + S.PDiag(diag::err_switch_incomplete_class_type) << CondExpr->getSourceRange())) return true; - llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions; - llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions; + UnresolvedSet<4> ViableConversions; + UnresolvedSet<4> ExplicitConversions; if (const RecordType *RecordTy = CondType->getAs<RecordType>()) { const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(RecordTy->getDecl()) ->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { - if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I)) + if (CXXConversionDecl *Conversion + = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) if (Conversion->getConversionType().getNonReferenceType() ->isIntegralType()) { if (Conversion->isExplicit()) - ExplicitConversions.push_back(Conversion); + ExplicitConversions.addDecl(I.getDecl(), I.getAccess()); else - ViableConversions.push_back(Conversion); + ViableConversions.addDecl(I.getDecl(), I.getAccess()); } } switch (ViableConversions.size()) { case 0: if (ExplicitConversions.size() == 1) { + DeclAccessPair Found = ExplicitConversions[0]; + CXXConversionDecl *Conversion = + cast<CXXConversionDecl>(Found->getUnderlyingDecl()); // The user probably meant to invoke the given explicit // conversion; use it. QualType ConvTy - = ExplicitConversions[0]->getConversionType() - .getNonReferenceType(); + = Conversion->getConversionType().getNonReferenceType(); std::string TypeStr; ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy); S.Diag(SwitchLoc, diag::err_switch_explicit_conversion) << CondType << ConvTy << CondExpr->getSourceRange() - << CodeModificationHint::CreateInsertion(CondExpr->getLocStart(), - "static_cast<" + TypeStr + ">(") - << CodeModificationHint::CreateInsertion( + << FixItHint::CreateInsertion(CondExpr->getLocStart(), + "static_cast<" + TypeStr + ">(") + << FixItHint::CreateInsertion( S.PP.getLocForEndOfToken(CondExpr->getLocEnd()), ")"); - S.Diag(ExplicitConversions[0]->getLocation(), - diag::note_switch_conversion) + S.Diag(Conversion->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; // If we aren't in a SFINAE context, build a call to the @@ -476,25 +484,32 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, if (S.isSFINAEContext()) return true; - CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]); + S.CheckMemberOperatorAccess(CondExpr->getExprLoc(), + CondExpr, 0, Found); + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, Conversion); } // We'll complain below about a non-integral condition type. break; - case 1: + case 1: { // Apply this conversion. - CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]); + DeclAccessPair Found = ViableConversions[0]; + S.CheckMemberOperatorAccess(CondExpr->getExprLoc(), + CondExpr, 0, Found); + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, + cast<CXXConversionDecl>(Found->getUnderlyingDecl())); break; + } default: S.Diag(SwitchLoc, diag::err_switch_multiple_conversions) << CondType << CondExpr->getSourceRange(); for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) { - QualType ConvTy - = ViableConversions[I]->getConversionType().getNonReferenceType(); - S.Diag(ViableConversions[I]->getLocation(), - diag::note_switch_conversion) + CXXConversionDecl *Conv + = cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl()); + QualType ConvTy = Conv->getConversionType().getNonReferenceType(); + S.Diag(Conv->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; } return true; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 434d556..40ec4bcb 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -161,7 +161,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep(); Diag(IILoc, diag::err_template_kw_missing) << Qualifier << II.getName() - << CodeModificationHint::CreateInsertion(IILoc, "template "); + << FixItHint::CreateInsertion(IILoc, "template "); SuggestedTemplate = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II)); SuggestedKind = TNK_Dependent_template_name; @@ -240,12 +240,12 @@ void Sema::LookupTemplateName(LookupResult &Found, if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_template_suggest) << Name << LookupCtx << Found.getLookupName() << SS.getRange() - << CodeModificationHint::CreateReplacement(Found.getNameLoc(), + << FixItHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); else Diag(Found.getNameLoc(), diag::err_no_template_suggest) << Name << Found.getLookupName() - << CodeModificationHint::CreateReplacement(Found.getNameLoc(), + << FixItHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>()) Diag(Template->getLocation(), diag::note_previous_decl) @@ -822,8 +822,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) { Diag(KWLoc, diag::err_use_with_wrong_tag) << Name - << CodeModificationHint::CreateReplacement(KWLoc, - PrevRecordDecl->getKindName()); + << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName()); Diag(PrevRecordDecl->getLocation(), diag::note_previous_use); Kind = PrevRecordDecl->getTagKind(); } @@ -1295,8 +1294,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, } else { Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header) << SS.getRange() - << CodeModificationHint::CreateInsertion(FirstTemplateLoc, - "template<> "); + << FixItHint::CreateInsertion(FirstTemplateLoc, "template<> "); IsExplicitSpecialization = true; } return 0; @@ -1499,8 +1497,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) << Type - << CodeModificationHint::CreateReplacement(SourceRange(TagLoc), - D->getKindName()); + << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); Diag(D->getLocation(), diag::note_previous_use); } } @@ -1897,7 +1894,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, - TemplateArgumentListBuilder &Converted) { + TemplateArgumentListBuilder &Converted, + CheckTemplateArgumentKind CTAK) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) return CheckTemplateTypeArgument(TTP, Arg, Converted); @@ -1937,7 +1935,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Expression: { Expr *E = Arg.getArgument().getAsExpr(); TemplateArgument Result; - if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) + if (CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK)) return true; Converted.Append(Result); @@ -2268,18 +2266,20 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, /// \brief Checks whether the given template argument is the address /// of an object or function according to C++ [temp.arg.nontype]p1. -bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, - NamedDecl *&Entity) { +static bool +CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, + NonTypeTemplateParmDecl *Param, + QualType ParamType, + Expr *ArgIn, + TemplateArgument &Converted) { bool Invalid = false; + Expr *Arg = ArgIn; + QualType ArgType = Arg->getType(); // See through any implicit casts we added to fix the type. while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) Arg = Cast->getSubExpr(); - // C++0x allows nullptr, and there's no further checking to be done for that. - if (Arg->getType()->isNullPtrType()) - return false; - // C++ [temp.arg.nontype]p1: // // A template-argument for a non-type, non-template @@ -2296,8 +2296,8 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, // Ignore (and complain about) any excess parentheses. while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) { if (!Invalid) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_extra_parens) + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_extra_parens) << Arg->getSourceRange(); Invalid = true; } @@ -2305,77 +2305,227 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, Arg = Parens->getSubExpr(); } + bool AddressTaken = false; + SourceLocation AddrOpLoc; if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) { - if (UnOp->getOpcode() == UnaryOperator::AddrOf) + if (UnOp->getOpcode() == UnaryOperator::AddrOf) { DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr()); + AddressTaken = true; + AddrOpLoc = UnOp->getOperatorLoc(); + } } else DRE = dyn_cast<DeclRefExpr>(Arg); - if (!DRE) - return Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_not_decl_ref) - << Arg->getSourceRange(); + if (!DRE) { + if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) { + S.Diag(Arg->getLocStart(), + diag::err_template_arg_unresolved_overloaded_function) + << ParamType << Arg->getSourceRange(); + } else { + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) + << Arg->getSourceRange(); + } + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } // Stop checking the precise nature of the argument if it is value dependent, // it should be checked when instantiated. - if (Arg->isValueDependent()) + if (Arg->isValueDependent()) { + Converted = TemplateArgument(ArgIn->Retain()); return false; + } - if (!isa<ValueDecl>(DRE->getDecl())) - return Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_not_object_or_func_form) + if (!isa<ValueDecl>(DRE->getDecl())) { + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_object_or_func_form) << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + NamedDecl *Entity = 0; // Cannot refer to non-static data members - if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl())) - return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field) + if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl())) { + S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field) << Field << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } // Cannot refer to non-static member functions if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl())) - if (!Method->isStatic()) - return Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_method) + if (!Method->isStatic()) { + S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_method) << Method << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } // Functions must have external linkage. if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) { if (!isExternalLinkage(Func->getLinkage())) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_function_not_extern) + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_function_not_extern) << Func << Arg->getSourceRange(); - Diag(Func->getLocation(), diag::note_template_arg_internal_object) + S.Diag(Func->getLocation(), diag::note_template_arg_internal_object) << true; return true; } // Okay: we've named a function with external linkage. Entity = Func; - return Invalid; - } - if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { + // If the template parameter has pointer type, the function decays. + if (ParamType->isPointerType() && !AddressTaken) + ArgType = S.Context.getPointerType(Func->getType()); + else if (AddressTaken && ParamType->isReferenceType()) { + // If we originally had an address-of operator, but the + // parameter has reference type, complain and (if things look + // like they will work) drop the address-of operator. + if (!S.Context.hasSameUnqualifiedType(Func->getType(), + ParamType.getNonReferenceType())) { + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType; + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType + << FixItHint::CreateRemoval(AddrOpLoc); + S.Diag(Param->getLocation(), diag::note_template_param_here); + + ArgType = Func->getType(); + } + } else if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { if (!isExternalLinkage(Var->getLinkage())) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_object_not_extern) + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_object_not_extern) << Var << Arg->getSourceRange(); - Diag(Var->getLocation(), diag::note_template_arg_internal_object) + S.Diag(Var->getLocation(), diag::note_template_arg_internal_object) << true; return true; } + // A value of reference type is not an object. + if (Var->getType()->isReferenceType()) { + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_reference_var) + << Var->getType() << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + // Okay: we've named an object with external linkage Entity = Var; - return Invalid; - } - // We found something else, but we don't know specifically what it is. - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_not_object_or_func) + // If the template parameter has pointer type, we must have taken + // the address of this object. + if (ParamType->isReferenceType()) { + if (AddressTaken) { + // If we originally had an address-of operator, but the + // parameter has reference type, complain and (if things look + // like they will work) drop the address-of operator. + if (!S.Context.hasSameUnqualifiedType(Var->getType(), + ParamType.getNonReferenceType())) { + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType; + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType + << FixItHint::CreateRemoval(AddrOpLoc); + S.Diag(Param->getLocation(), diag::note_template_param_here); + + ArgType = Var->getType(); + } + } else if (!AddressTaken && ParamType->isPointerType()) { + if (Var->getType()->isArrayType()) { + // Array-to-pointer decay. + ArgType = S.Context.getArrayDecayedType(Var->getType()); + } else { + // If the template parameter has pointer type but the address of + // this object was not taken, complain and (possibly) recover by + // taking the address of the entity. + ArgType = S.Context.getPointerType(Var->getType()); + if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) { + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of) + << ParamType; + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of) + << ParamType + << FixItHint::CreateInsertion(Arg->getLocStart(), "&"); + + S.Diag(Param->getLocation(), diag::note_template_param_here); + } + } + } else { + // We found something else, but we don't know specifically what it is. + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_object_or_func) << Arg->getSourceRange(); - Diag(DRE->getDecl()->getLocation(), - diag::note_template_arg_refers_here); - return true; + S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here); + return true; + } + + if (ParamType->isPointerType() && + !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() && + S.IsQualificationConversion(ArgType, ParamType)) { + // For pointer-to-object types, qualification conversions are + // permitted. + } else { + if (const ReferenceType *ParamRef = ParamType->getAs<ReferenceType>()) { + if (!ParamRef->getPointeeType()->isFunctionType()) { + // C++ [temp.arg.nontype]p5b3: + // For a non-type template-parameter of type reference to + // object, no conversions apply. The type referred to by the + // reference may be more cv-qualified than the (otherwise + // identical) type of the template- argument. The + // template-parameter is bound directly to the + // template-argument, which shall be an lvalue. + + // FIXME: Other qualifiers? + unsigned ParamQuals = ParamRef->getPointeeType().getCVRQualifiers(); + unsigned ArgQuals = ArgType.getCVRQualifiers(); + + if ((ParamQuals | ArgQuals) != ParamQuals) { + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_ref_bind_ignores_quals) + << ParamType << Arg->getType() + << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + } + } + + // At this point, the template argument refers to an object or + // function with external linkage. We now need to check whether the + // argument and parameter types are compatible. + if (!S.Context.hasSameUnqualifiedType(ArgType, + ParamType.getNonReferenceType())) { + // We can't perform this conversion or binding. + if (ParamType->isReferenceType()) + S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind) + << ParamType << Arg->getType() << Arg->getSourceRange(); + else + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible) + << Arg->getType() << ParamType << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + } + + // Create the template argument. + Converted = TemplateArgument(Entity->getCanonicalDecl()); + return false; } /// \brief Checks whether the given template argument is a pointer to @@ -2388,10 +2538,6 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) Arg = Cast->getSubExpr(); - // C++0x allows nullptr, and there's no further checking to be done for that. - if (Arg->getType()->isNullPtrType()) - return false; - // C++ [temp.arg.nontype]p1: // // A template-argument for a non-type, non-template @@ -2478,12 +2624,12 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, /// If no error was detected, Converted receives the converted template argument. bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, - TemplateArgument &Converted) { + TemplateArgument &Converted, + CheckTemplateArgumentKind CTAK) { SourceLocation StartLoc = Arg->getSourceRange().getBegin(); // If either the parameter has a dependent type or the argument is // type-dependent, there's nothing we can check now. - // FIXME: Add template argument to Converted! if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) { // FIXME: Produce a cloned, canonical expression? Converted = TemplateArgument(Arg); @@ -2525,17 +2671,27 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; } - // FIXME: We need some way to more easily get the unqualified form - // of the types without going all the way to the - // canonical type. - if (Context.getCanonicalType(ParamType).getCVRQualifiers()) - ParamType = Context.getCanonicalType(ParamType).getUnqualifiedType(); - if (Context.getCanonicalType(ArgType).getCVRQualifiers()) - ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType(); + // From here on out, all we care about are the unqualified forms + // of the parameter and argument types. + ParamType = ParamType.getUnqualifiedType(); + ArgType = ArgType.getUnqualifiedType(); // Try to convert the argument to the parameter's type. if (Context.hasSameType(ParamType, ArgType)) { // Okay: no conversion necessary + } else if (CTAK == CTAK_Deduced) { + // C++ [temp.deduct.type]p17: + // If, in the declaration of a function template with a non-type + // template-parameter, the non-type template- parameter is used + // in an expression in the function parameter-list and, if the + // corresponding template-argument is deduced, the + // template-argument type shall match the type of the + // template-parameter exactly, except that a template-argument + // deduced from an array bound may be of any integral type. + Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch) + << ArgType << ParamType; + Diag(Param->getLocation(), diag::note_template_param_here); + return true; } else if (IsIntegralPromotion(Arg, ArgType, ParamType) || !ParamType->isEnumeralType()) { // This is an integral promotion or conversion. @@ -2554,38 +2710,39 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); if (!Arg->isValueDependent()) { - // Check that an unsigned parameter does not receive a negative - // value. + llvm::APSInt OldValue = Value; + + // Coerce the template argument's value to the value it will have + // based on the template parameter's type. + unsigned AllowedBits = Context.getTypeSize(IntegerType); + if (Value.getBitWidth() != AllowedBits) + Value.extOrTrunc(AllowedBits); + Value.setIsSigned(IntegerType->isSignedIntegerType()); + + // Complain if an unsigned parameter received a negative value. if (IntegerType->isUnsignedIntegerType() - && (Value.isSigned() && Value.isNegative())) { - Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_negative) - << Value.toString(10) << Param->getType() + && (OldValue.isSigned() && OldValue.isNegative())) { + Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative) + << OldValue.toString(10) << Value.toString(10) << Param->getType() << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); - return true; } - // Check that we don't overflow the template parameter type. - unsigned AllowedBits = Context.getTypeSize(IntegerType); + // Complain if we overflowed the template parameter's type. unsigned RequiredBits; if (IntegerType->isUnsignedIntegerType()) - RequiredBits = Value.getActiveBits(); - else if (Value.isUnsigned()) - RequiredBits = Value.getActiveBits() + 1; + RequiredBits = OldValue.getActiveBits(); + else if (OldValue.isUnsigned()) + RequiredBits = OldValue.getActiveBits() + 1; else - RequiredBits = Value.getMinSignedBits(); + RequiredBits = OldValue.getMinSignedBits(); if (RequiredBits > AllowedBits) { Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_too_large) - << Value.toString(10) << Param->getType() + diag::warn_template_arg_too_large) + << OldValue.toString(10) << Value.toString(10) << Param->getType() << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); - return true; } - - if (Value.getBitWidth() != AllowedBits) - Value.extOrTrunc(AllowedBits); - Value.setIsSigned(IntegerType->isSignedIntegerType()); } // Add the value of this argument to the list of converted @@ -2604,6 +2761,18 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return false; } + DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction + + // C++0x [temp.arg.nontype]p5 bullets 2, 4 and 6 permit conversion + // from a template argument of type std::nullptr_t to a non-type + // template parameter of type pointer to object, pointer to + // function, or pointer-to-member, respectively. + if (ArgType->isNullPtrType() && + (ParamType->isPointerType() || ParamType->isMemberPointerType())) { + Converted = TemplateArgument((NamedDecl *)0); + return false; + } + // Handle pointer-to-function, reference-to-function, and // pointer-to-member-function all in (roughly) the same way. if (// -- For a non-type template-parameter of type pointer to @@ -2611,7 +2780,6 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // applied. If the template-argument represents a set of // overloaded functions (or a pointer to such), the matching // function is selected from the set (13.4). - // In C++0x, any std::nullptr_t value can be converted. (ParamType->isPointerType() && ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) || // -- For a non-type template-parameter of type reference to @@ -2625,38 +2793,30 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // template-argument represents a set of overloaded member // functions, the matching member function is selected from // the set (13.4). - // Again, C++0x allows a std::nullptr_t value. (ParamType->isMemberPointerType() && ParamType->getAs<MemberPointerType>()->getPointeeType() ->isFunctionType())) { - if (Context.hasSameUnqualifiedType(ArgType, - ParamType.getNonReferenceType())) { - // We don't have to do anything: the types already match. - } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() || - ParamType->isMemberPointerType())) { - ArgType = ParamType; - if (ParamType->isMemberPointerType()) - ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer); - else - ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast); - } else if (ArgType->isFunctionType() && ParamType->isPointerType()) { - ArgType = Context.getPointerType(ArgType); - ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay); - } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) { + + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, + true, + FoundResult)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) return true; - Arg = FixOverloadedFunctionReference(Arg, Fn); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); ArgType = Arg->getType(); - if (ArgType->isFunctionType() && ParamType->isPointerType()) { - ArgType = Context.getPointerType(Arg->getType()); - ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay); - } } - if (!Context.hasSameUnqualifiedType(ArgType, - ParamType.getNonReferenceType())) { + if (!ParamType->isMemberPointerType()) + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted); + + if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType())) { + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp, + Arg->isLvalue(Context) == Expr::LV_Valid); + } else if (!Context.hasSameUnqualifiedType(ArgType, + ParamType.getNonReferenceType())) { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) @@ -2665,21 +2825,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; } - if (ParamType->isMemberPointerType()) - return CheckTemplateArgumentPointerToMember(Arg, Converted); - - NamedDecl *Entity = 0; - if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) - return true; - - if (Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); - } else { - if (Entity) - Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); - } - return false; + return CheckTemplateArgumentPointerToMember(Arg, Converted); } if (ParamType->isPointerType()) { @@ -2690,40 +2836,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamType->getAs<PointerType>()->getPointeeType()->isObjectType() && "Only object pointers allowed here"); - if (ArgType->isNullPtrType()) { - ArgType = ParamType; - ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast); - } else if (ArgType->isArrayType()) { - ArgType = Context.getArrayDecayedType(ArgType); - ImpCastExprToType(Arg, ArgType, CastExpr::CK_ArrayToPointerDecay); - } - - if (IsQualificationConversion(ArgType, ParamType)) { - ArgType = ParamType; - ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp); - } - - if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) { - // 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; - } - - NamedDecl *Entity = 0; - if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) - return true; - - if (Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); - } else { - if (Entity) - Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); - } - return false; + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted); } if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) { @@ -2736,53 +2851,31 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamRefType->getPointeeType()->isObjectType() && "Only object references allowed here"); - QualType ReferredType = ParamRefType->getPointeeType(); - if (!Context.hasSameUnqualifiedType(ReferredType, ArgType)) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_no_ref_bind) - << InstantiatedParamType << Arg->getType() - << Arg->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - - unsigned ParamQuals - = Context.getCanonicalType(ReferredType).getCVRQualifiers(); - unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers(); + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, + ParamRefType->getPointeeType(), + true, + FoundResult)) { + if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) + return true; - if ((ParamQuals | ArgQuals) != ParamQuals) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_ref_bind_ignores_quals) - << InstantiatedParamType << Arg->getType() - << Arg->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); - return true; + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + ArgType = Arg->getType(); } - NamedDecl *Entity = 0; - if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) - return true; - - if (Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); - } else { - Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); - } - return false; + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted); } // -- For a non-type template-parameter of type pointer to data // member, qualification conversions (4.4) are applied. - // C++0x allows std::nullptr_t values. assert(ParamType->isMemberPointerType() && "Only pointers to members remain"); if (Context.hasSameUnqualifiedType(ParamType, ArgType)) { // Types match exactly: nothing more to do here. - } else if (ArgType->isNullPtrType()) { - ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer); } else if (IsQualificationConversion(ArgType, ParamType)) { - ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp, + Arg->isLvalue(Context) == Expr::LV_Valid); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), @@ -2837,6 +2930,109 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, Arg.getLocation()); } +/// \brief Given a non-type template argument that refers to a +/// declaration and the type of its corresponding non-type template +/// parameter, produce an expression that properly refers to that +/// declaration. +Sema::OwningExprResult +Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, + QualType ParamType, + SourceLocation Loc) { + assert(Arg.getKind() == TemplateArgument::Declaration && + "Only declaration template arguments permitted here"); + ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); + + if (VD->getDeclContext()->isRecord() && + (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) { + // If the value is a class member, we might have a pointer-to-member. + // Determine whether the non-type template template parameter is of + // pointer-to-member type. If so, we need to build an appropriate + // expression for a pointer-to-member, since a "normal" DeclRefExpr + // would refer to the member itself. + if (ParamType->isMemberPointerType()) { + QualType ClassType + = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext())); + NestedNameSpecifier *Qualifier + = NestedNameSpecifier::Create(Context, 0, false, ClassType.getTypePtr()); + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + OwningExprResult RefExpr = BuildDeclRefExpr(VD, + VD->getType().getNonReferenceType(), + Loc, + &SS); + if (RefExpr.isInvalid()) + return ExprError(); + + RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr)); + assert(!RefExpr.isInvalid() && + Context.hasSameType(((Expr*) RefExpr.get())->getType(), + ParamType)); + return move(RefExpr); + } + } + + QualType T = VD->getType().getNonReferenceType(); + if (ParamType->isPointerType()) { + // When the non-type template parameter is a pointer, take the + // address of the declaration. + OwningExprResult RefExpr = BuildDeclRefExpr(VD, T, Loc); + if (RefExpr.isInvalid()) + return ExprError(); + + 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); + } + + return move(RefExpr); + } + + // Take the address of everything else + return CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr)); + } + + // If the non-type template parameter has reference type, qualify the + // resulting declaration reference with the extra qualifiers on the + // type that the reference refers to. + if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>()) + T = Context.getQualifiedType(T, TargetRef->getPointeeType().getQualifiers()); + + return BuildDeclRefExpr(VD, T, Loc); +} + +/// \brief Construct a new expression that refers to the given +/// integral template argument with the given source-location +/// information. +/// +/// This routine takes care of the mapping from an integral template +/// argument (which may have any integral type) to the appropriate +/// literal value. +Sema::OwningExprResult +Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, + SourceLocation Loc) { + assert(Arg.getKind() == TemplateArgument::Integral && + "Operation is only value for integral template arguments"); + QualType T = Arg.getIntegralType(); + if (T->isCharType() || T->isWideCharType()) + return Owned(new (Context) CharacterLiteral( + Arg.getAsIntegral()->getZExtValue(), + T->isWideCharType(), + T, + Loc)); + if (T->isBooleanType()) + return Owned(new (Context) CXXBoolLiteralExpr( + Arg.getAsIntegral()->getBoolValue(), + T, + Loc)); + + return Owned(new (Context) IntegerLiteral(*Arg.getAsIntegral(), T, Loc)); +} + + /// \brief Determine whether the given template parameter lists are /// equivalent. /// @@ -3341,7 +3537,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } else if (TemplateParams) { if (TUK == TUK_Friend) Diag(KWLoc, diag::err_template_spec_friend) - << CodeModificationHint::CreateRemoval( + << FixItHint::CreateRemoval( SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc())) << SourceRange(LAngleLoc, RAngleLoc); @@ -3349,7 +3545,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, isExplicitSpecialization = true; } else if (TUK != TUK_Friend) { Diag(KWLoc, diag::err_template_spec_needs_header) - << CodeModificationHint::CreateInsertion(KWLoc, "template<> "); + << FixItHint::CreateInsertion(KWLoc, "template<> "); isExplicitSpecialization = true; } @@ -3367,7 +3563,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate - << CodeModificationHint::CreateReplacement(KWLoc, + << FixItHint::CreateReplacement(KWLoc, ClassTemplate->getTemplatedDecl()->getKindName()); Diag(ClassTemplate->getTemplatedDecl()->getLocation(), diag::note_previous_use); @@ -3409,8 +3605,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // to the implicit argument list of the primary template. Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) << (TUK == TUK_Definition) - << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc, - RAngleLoc)); + << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(), TemplateNameLoc, @@ -3644,7 +3839,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (TUK == TUK_Friend) { FriendDecl *Friend = FriendDecl::Create(Context, CurContext, TemplateNameLoc, - WrittenTy->getType().getTypePtr(), + WrittenTy, /*FIXME:*/KWLoc); Friend->setAccess(AS_public); CurContext->addDecl(Friend); @@ -3948,11 +4143,11 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, UnresolvedSetIterator Result = getMostSpecialized(Candidates.begin(), Candidates.end(), TPOC_Other, FD->getLocation(), - PartialDiagnostic(diag::err_function_template_spec_no_match) + PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(), - PartialDiagnostic(diag::err_function_template_spec_ambiguous) + PDiag(diag::err_function_template_spec_ambiguous) << FD->getDeclName() << (ExplicitTemplateArgs != 0), - PartialDiagnostic(diag::note_function_template_spec_matched)); + PDiag(diag::note_function_template_spec_matched)); if (Result == Candidates.end()) return true; @@ -3961,9 +4156,14 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . + + // If this is a friend declaration, then we're not really declaring + // an explicit specialization. + bool isFriend = (FD->getFriendObjectKind() != Decl::FOK_None); // Check the scope of this explicit specialization. - if (CheckTemplateSpecializationScope(*this, + if (!isFriend && + CheckTemplateSpecializationScope(*this, Specialization->getPrimaryTemplate(), Specialization, FD->getLocation(), false)) @@ -3980,7 +4180,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, assert(SpecInfo && "Function template specialization info missing?"); bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(FD->getLocation(), + if (!isFriend && + CheckSpecializationInstantiationRedecl(FD->getLocation(), TSK_ExplicitSpecialization, Specialization, SpecInfo->getTemplateSpecializationKind(), @@ -3990,7 +4191,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. - SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); + if (!isFriend) + SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); // Turn the given function declaration into a function template // specialization, with the template arguments from the previous @@ -3999,7 +4201,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, new (Context) TemplateArgumentList( *Specialization->getTemplateSpecializationArgs()), /*InsertPos=*/0, - TSK_ExplicitSpecialization); + SpecInfo->getTemplateSpecializationKind()); // The "previous declaration" for this function template specialization is // the prior function template specialization. @@ -4250,7 +4452,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate - << CodeModificationHint::CreateReplacement(KWLoc, + << FixItHint::CreateReplacement(KWLoc, ClassTemplate->getTemplatedDecl()->getKindName()); Diag(ClassTemplate->getTemplatedDecl()->getLocation(), diag::note_previous_use); @@ -4388,8 +4590,17 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Instantiate the members of this class template specialization. Def = cast_or_null<ClassTemplateSpecializationDecl>( Specialization->getDefinition()); - if (Def) + if (Def) { + TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind(); + + // Fix a TSK_ExplicitInstantiationDeclaration followed by a + // TSK_ExplicitInstantiationDefinition + if (Old_TSK == TSK_ExplicitInstantiationDeclaration && + TSK == TSK_ExplicitInstantiationDefinition) + Def->setTemplateSpecializationKind(TSK); + InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); + } return DeclPtrTy::make(Specialization); } @@ -4559,7 +4770,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_explicit_instantiation_inline) - <<CodeModificationHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); + <<FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); // FIXME: check for constexpr specifier. @@ -4699,9 +4910,9 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, UnresolvedSetIterator Result = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, D.getIdentifierLoc(), - PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name, - PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name, - PartialDiagnostic(diag::note_explicit_instantiation_candidate)); + PDiag(diag::err_explicit_instantiation_not_known) << Name, + PDiag(diag::err_explicit_instantiation_ambiguous) << Name, + PDiag(diag::note_explicit_instantiation_candidate)); if (Result == Matches.end()) return true; @@ -4781,14 +4992,16 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (!NNS) return true; - QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc)); - if (T.isNull()) - return true; - - TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); - QualType ElabType = Context.getElaboratedType(T, TagKind); + ElaboratedTypeKeyword Keyword = ETK_None; + switch (TagDecl::getTagKindForTypeSpec(TagSpec)) { + case TagDecl::TK_struct: Keyword = ETK_Struct; break; + case TagDecl::TK_class: Keyword = ETK_Class; break; + case TagDecl::TK_union: Keyword = ETK_Union; break; + case TagDecl::TK_enum: Keyword = ETK_Enum; break; + } + assert(Keyword != ETK_None && "Invalid tag kind!"); - return ElabType.getAsOpaquePtr(); + return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr(); } Sema::TypeResult @@ -4824,7 +5037,8 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr(); } - return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr(); + return Context.getDependentNameType(ETK_Typename, NNS, TemplateId) + .getAsOpaquePtr(); } /// \brief Build the type that describes a C++ typename specifier, @@ -4839,7 +5053,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, // If the nested-name-specifier does not refer to the current // instantiation, then build a typename type. if (!CurrentInstantiation) - return Context.getTypenameType(NNS, &II); + return Context.getDependentNameType(ETK_Typename, NNS, &II); // The nested-name-specifier refers to the current instantiation, so the // "typename" keyword itself is superfluous. In C++03, the program is @@ -4875,7 +5089,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. - return Context.getTypenameType(NNS, &II); + return Context.getDependentNameType(ETK_Typename, NNS, &II); case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { @@ -4960,16 +5174,16 @@ namespace { /// \brief Transforms a typename type by determining whether the type now /// refers to a member of the current instantiation, and then /// type-checking and building a QualifiedNameType (when possible). - QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL, + QualType TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL, QualType ObjectType); }; } QualType -CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, - TypenameTypeLoc TL, +CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, + DependentNameTypeLoc TL, QualType ObjectType) { - TypenameType *T = TL.getTypePtr(); + DependentNameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), @@ -5001,15 +5215,17 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, NewTemplateId == QualType(TemplateId, 0)) Result = QualType(T, 0); else - Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), + NNS, NewTemplateId); } else - Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), - SourceRange(TL.getNameLoc())); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), + NNS, T->getIdentifier(), + SourceRange(TL.getNameLoc())); if (Result.isNull()) return QualType(); - TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); + DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } @@ -5034,7 +5250,7 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, /// typename X<T>::pointer X<T>::data() { ... } /// \endcode /// -/// Here, the type "typename X<T>::pointer" will be created as a TypenameType, +/// Here, the type "typename X<T>::pointer" will be created as a DependentNameType, /// since we do not know that we can look into X<T> when we parsed the type. /// This function will rebuild the type, performing the lookup of "pointer" /// in X<T> and returning a QualifiedNameType whose canonical type is the same diff --git a/lib/Sema/SemaTemplate.h b/lib/Sema/SemaTemplate.h index 2bfb25a..ca59e27 100644 --- a/lib/Sema/SemaTemplate.h +++ b/lib/Sema/SemaTemplate.h @@ -99,6 +99,40 @@ namespace clang { /// template specialization to a function template. TPOC_Other }; + + /// \brief Captures a template argument whose value has been deduced + /// via c++ template argument deduction. + class DeducedTemplateArgument : public TemplateArgument { + /// \brief For a non-type template argument, whether the value was + /// deduced from an array bound. + bool DeducedFromArrayBound; + + public: + DeducedTemplateArgument() + : TemplateArgument(), DeducedFromArrayBound(false) { } + + DeducedTemplateArgument(const TemplateArgument &Arg, + bool DeducedFromArrayBound = false) + : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { } + + /// \brief Construct an integral non-type template argument that + /// has been deduced, possible from an array bound. + DeducedTemplateArgument(const llvm::APSInt &Value, + QualType ValueType, + bool DeducedFromArrayBound) + : TemplateArgument(Value, ValueType), + DeducedFromArrayBound(DeducedFromArrayBound) { } + + /// \brief For a non-type template argument, determine whether the + /// template argument was deduced from an array bound. + bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; } + + /// \brief Specify whether the given non-type template argument + /// was deduced from an array bound. + void setDeducedFromArrayBound(bool Deduced) { + DeducedFromArrayBound = Deduced; + } + }; } #endif // LLVM_CLANG_SEMA_TEMPLATE_H diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 326519d..d61a767 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -48,13 +48,34 @@ namespace clang { using namespace clang; +/// \brief Compare two APSInts, extending and switching the sign as +/// necessary to compare their values regardless of underlying type. +static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { + if (Y.getBitWidth() > X.getBitWidth()) + X.extend(Y.getBitWidth()); + else if (Y.getBitWidth() < X.getBitWidth()) + Y.extend(X.getBitWidth()); + + // If there is a signedness mismatch, correct it. + if (X.isSigned() != Y.isSigned()) { + // If the signed value is negative, then the values cannot be the same. + if ((Y.isSigned() && Y.isNegative()) || (X.isSigned() && X.isNegative())) + return false; + + Y.setIsSigned(true); + X.setIsSigned(true); + } + + return X == Y; +} + static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument &Param, const TemplateArgument &Arg, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced); + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced); /// \brief If the given expression is of a form that permits the deduction /// of a non-type template parameter, return the declaration of that @@ -74,50 +95,38 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, - llvm::APSInt Value, + llvm::APSInt Value, QualType ValueType, + bool DeducedFromArrayBound, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); if (Deduced[NTTP->getIndex()].isNull()) { - QualType T = NTTP->getType(); - - // FIXME: Make sure we didn't overflow our data type! - unsigned AllowedBits = S.Context.getTypeSize(T); - if (Value.getBitWidth() != AllowedBits) - Value.extOrTrunc(AllowedBits); - Value.setIsSigned(T->isSignedIntegerType()); - - Deduced[NTTP->getIndex()] = TemplateArgument(Value, T); + Deduced[NTTP->getIndex()] = DeducedTemplateArgument(Value, ValueType, + DeducedFromArrayBound); return Sema::TDK_Success; } - assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral); - - // If the template argument was previously deduced to a negative value, - // then our deduction fails. - const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral(); - if (PrevValuePtr->isNegative()) { + if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(Value, NTTP->getType()); - return Sema::TDK_Inconsistent; + Info.SecondArg = TemplateArgument(Value, ValueType); + return Sema::TDK_Inconsistent; } - llvm::APSInt PrevValue = *PrevValuePtr; - if (Value.getBitWidth() > PrevValue.getBitWidth()) - PrevValue.zext(Value.getBitWidth()); - else if (Value.getBitWidth() < PrevValue.getBitWidth()) - Value.zext(PrevValue.getBitWidth()); - - if (Value != PrevValue) { + // Extent the smaller of the two values. + llvm::APSInt PrevValue = *Deduced[NTTP->getIndex()].getAsIntegral(); + if (!hasSameExtendedValue(PrevValue, Value)) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(Value, NTTP->getType()); + Info.SecondArg = TemplateArgument(Value, ValueType); return Sema::TDK_Inconsistent; } + if (!DeducedFromArrayBound) + Deduced[NTTP->getIndex()].setDeducedFromArrayBound(false); + return Sema::TDK_Success; } @@ -130,15 +139,14 @@ DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Expr *Value, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); assert((Value->isTypeDependent() || Value->isValueDependent()) && "Expression template argument must be type- or value-dependent."); if (Deduced[NTTP->getIndex()].isNull()) { - // FIXME: Clone the Value? - Deduced[NTTP->getIndex()] = TemplateArgument(Value); + Deduced[NTTP->getIndex()] = TemplateArgument(Value->Retain()); return Sema::TDK_Success; } @@ -173,7 +181,7 @@ DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Decl *D, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); @@ -207,7 +215,7 @@ DeduceTemplateArguments(Sema &S, TemplateName Param, TemplateName Arg, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); if (!ParamDecl) { // The parameter type is dependent and is not a template template parameter, @@ -271,7 +279,7 @@ DeduceTemplateArguments(Sema &S, const TemplateSpecializationType *Param, QualType Arg, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(Arg.isCanonical() && "Argument type must be canonical"); // Check whether the template argument is a dependent template-id. @@ -363,7 +371,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, QualType ParamIn, QualType ArgIn, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF) { // We only want to look at the canonical types, since typedefs and // sugar are not part of template argument deduction. @@ -569,7 +577,9 @@ DeduceTemplateArguments(Sema &S, if (const ConstantArrayType *ConstantArrayArg = dyn_cast<ConstantArrayType>(ArrayArg)) { llvm::APSInt Size(ConstantArrayArg->getSize()); - return DeduceNonTypeTemplateArgument(S, NTTP, Size, + return DeduceNonTypeTemplateArgument(S, NTTP, Size, + S.Context.getSizeType(), + /*ArrayBound=*/true, Info, Deduced); } if (const DependentSizedArrayType *DependentArrayArg @@ -763,7 +773,7 @@ DeduceTemplateArguments(Sema &S, case Type::TypeOfExpr: case Type::TypeOf: - case Type::Typename: + case Type::DependentName: // No template argument deduction for these types return Sema::TDK_Success; @@ -781,7 +791,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument &Param, const TemplateArgument &Arg, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { switch (Param.getKind()) { case TemplateArgument::Null: assert(false && "Null template argument in parameter list"); @@ -816,8 +826,7 @@ DeduceTemplateArguments(Sema &S, case TemplateArgument::Integral: if (Arg.getKind() == TemplateArgument::Integral) { - // FIXME: Zero extension + sign checking here? - if (*Param.getAsIntegral() == *Arg.getAsIntegral()) + if (hasSameExtendedValue(*Param.getAsIntegral(), *Arg.getAsIntegral())) return Sema::TDK_Success; Info.FirstArg = Param; @@ -840,9 +849,10 @@ DeduceTemplateArguments(Sema &S, if (NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Param.getAsExpr())) { if (Arg.getKind() == TemplateArgument::Integral) - // FIXME: Sign problems here return DeduceNonTypeTemplateArgument(S, NTTP, *Arg.getAsIntegral(), + Arg.getIntegralType(), + /*ArrayBound=*/false, Info, Deduced); if (Arg.getKind() == TemplateArgument::Expression) return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(), @@ -874,7 +884,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgumentList &ParamList, const TemplateArgumentList &ArgList, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(ParamList.size() == ArgList.size()); for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { if (Sema::TemplateDeductionResult Result @@ -963,7 +973,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // specialization can be deduced from the actual template argument // list (14.8.2). SFINAETrap Trap(*this); - llvm::SmallVector<TemplateArgument, 4> Deduced; + llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(Partial->getTemplateParameters()->size()); if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, @@ -987,13 +997,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Decl *Param = const_cast<NamedDecl *>( Partial->getTemplateParameters()->getParam(I)); - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) - Info.Param = TTP; - else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(Param)) - Info.Param = NTTP; - else - Info.Param = cast<TemplateTemplateParmDecl>(Param); + Info.Param = makeTemplateParameter(Param); return TDK_Incomplete; } @@ -1010,6 +1014,9 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // verify that the instantiated template arguments are both valid // and are equivalent to the template arguments originally provided // to the class template. + // FIXME: Do we have to correct the types of deduced non-type template + // arguments (in particular, integral non-type template arguments?). + Sema::LocalInstantiationScope InstScope(*this); ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); const TemplateArgumentLoc *PartialTemplateArgs = Partial->getTemplateArgsAsWritten(); @@ -1112,7 +1119,7 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, const TemplateArgumentListInfo &ExplicitTemplateArgs, - llvm::SmallVectorImpl<TemplateArgument> &Deduced, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, llvm::SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, TemplateDeductionInfo &Info) { @@ -1225,12 +1232,67 @@ Sema::SubstituteExplicitTemplateArguments( return TDK_Success; } +/// \brief Allocate a TemplateArgumentLoc where all locations have +/// been initialized to the given location. +/// +/// \param S The semantic analysis object. +/// +/// \param The template argument we are producing template argument +/// location information for. +/// +/// \param NTTPType For a declaration template argument, the type of +/// the non-type template parameter that corresponds to this template +/// argument. +/// +/// \param Loc The source location to use for the resulting template +/// argument. +static TemplateArgumentLoc +getTrivialTemplateArgumentLoc(Sema &S, + const TemplateArgument &Arg, + QualType NTTPType, + SourceLocation Loc) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Can't get a NULL template argument here"); + break; + + case TemplateArgument::Type: + return TemplateArgumentLoc(Arg, + S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); + + case TemplateArgument::Declaration: { + Expr *E + = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + .takeAs<Expr>(); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case TemplateArgument::Integral: { + Expr *E + = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>(); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case TemplateArgument::Template: + return TemplateArgumentLoc(Arg, SourceRange(), Loc); + + case TemplateArgument::Expression: + return TemplateArgumentLoc(Arg, Arg.getAsExpr()); + + case TemplateArgument::Pack: + llvm_unreachable("Template parameter packs are not yet supported"); + } + + return TemplateArgumentLoc(); +} + /// \brief Finish template argument deduction for a function template, /// checking the deduced template arguments for completeness and forming /// the function template specialization. Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl<TemplateArgument> &Deduced, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { TemplateParameterList *TemplateParams @@ -1253,13 +1315,71 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // explicitly specified, template argument deduction fails. TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size()); for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { + NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I); if (!Deduced[I].isNull()) { - Builder.Append(Deduced[I]); + if (I < NumExplicitlySpecified || + Deduced[I].getKind() == TemplateArgument::Type) { + // We have already fully type-checked and converted this + // argument (because it was explicitly-specified) or no + // additional checking is necessary (because it's a template + // type parameter). Just record the presence of this + // parameter. + Builder.Append(Deduced[I]); + continue; + } + + // We have deduced this argument, so it still needs to be + // checked and converted. + + // First, for a non-type template parameter type that is + // initialized by a declaration, we need the type of the + // corresponding non-type template parameter. + QualType NTTPType; + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + if (Deduced[I].getKind() == TemplateArgument::Declaration) { + NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + TemplateArgumentList TemplateArgs(Context, Builder, + /*TakeArgs=*/false); + NTTPType = SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + if (NTTPType.isNull()) { + Info.Param = makeTemplateParameter(Param); + return TDK_SubstitutionFailure; + } + } + } + } + + // Convert the deduced template argument into a template + // argument that we can check, almost as if the user had written + // the template argument explicitly. + TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this, + Deduced[I], + NTTPType, + SourceLocation()); + + // Check the template argument, converting it as necessary. + if (CheckTemplateArgument(Param, Arg, + FunctionTemplate, + FunctionTemplate->getLocation(), + FunctionTemplate->getSourceRange().getEnd(), + Builder, + Deduced[I].wasDeducedFromArrayBound() + ? CTAK_DeducedFromArrayBound + : CTAK_Deduced)) { + Info.Param = makeTemplateParameter( + const_cast<NamedDecl *>(TemplateParams->getParam(I))); + return TDK_SubstitutionFailure; + } + continue; } // Substitute into the default template argument, if available. - NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I); TemplateArgumentLoc DefArg = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate, FunctionTemplate->getLocation(), @@ -1279,7 +1399,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, FunctionTemplate, FunctionTemplate->getLocation(), FunctionTemplate->getSourceRange().getEnd(), - Builder)) { + Builder, + CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); return TDK_SubstitutionFailure; @@ -1390,7 +1511,8 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // Type deduction is done independently for each P/A pair, and // the deduced template argument values are then combined. // So we do not reject deductions which were made elsewhere. - llvm::SmallVector<TemplateArgument, 8> Deduced(TemplateParams->size()); + llvm::SmallVector<DeducedTemplateArgument, 8> + Deduced(TemplateParams->size()); Sema::TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); unsigned TDF = 0; @@ -1458,10 +1580,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // The types of the parameters from which we will perform template argument // deduction. + Sema::LocalInstantiationScope InstScope(*this); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector<TemplateArgument, 4> Deduced; + llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; llvm::SmallVector<QualType, 4> ParamTypes; + unsigned NumExplicitlySpecified = 0; if (ExplicitTemplateArgs) { TemplateDeductionResult Result = SubstituteExplicitTemplateArguments(FunctionTemplate, @@ -1472,6 +1596,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Info); if (Result) return Result; + + NumExplicitlySpecified = Deduced.size(); } else { // Just fill in the parameter types from the function declaration. for (unsigned I = 0; I != CheckArgs; ++I) @@ -1574,6 +1700,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, } return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + NumExplicitlySpecified, Specialization, Info); } @@ -1612,7 +1739,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType FunctionType = Function->getType(); // Substitute any explicit template arguments. - llvm::SmallVector<TemplateArgument, 4> Deduced; + Sema::LocalInstantiationScope InstScope(*this); + llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + unsigned NumExplicitlySpecified = 0; llvm::SmallVector<QualType, 4> ParamTypes; if (ExplicitTemplateArgs) { if (TemplateDeductionResult Result @@ -1621,6 +1750,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Deduced, ParamTypes, &FunctionType, Info)) return Result; + + NumExplicitlySpecified = Deduced.size(); } // Template argument deduction for function templates in a SFINAE context. @@ -1639,6 +1770,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, } return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + NumExplicitlySpecified, Specialization, Info); } @@ -1707,7 +1839,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // A) as described in 14.8.2.4. TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector<TemplateArgument, 4> Deduced; + llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(TemplateParams->size()); // C++0x [temp.deduct.conv]p4: @@ -1739,9 +1871,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // modulo the various allowed differences. // Finish template argument deduction. + Sema::LocalInstantiationScope InstScope(*this); FunctionDecl *Spec = 0; TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info); + = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec, + Info); Specialization = cast_or_null<CXXConversionDecl>(Spec); return Result; } @@ -1799,11 +1933,11 @@ enum DeductionQualifierComparison { /// but it may still fail, later, for other reasons. static Sema::TemplateDeductionResult DeduceTemplateArgumentsDuringPartialOrdering(Sema &S, - TemplateParameterList *TemplateParams, + TemplateParameterList *TemplateParams, QualType ParamIn, QualType ArgIn, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Deduced, - llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) { + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) { CanQualType Param = S.Context.getCanonicalType(ParamIn); CanQualType Arg = S.Context.getCanonicalType(ArgIn); @@ -1877,7 +2011,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, assert(Proto1 && Proto2 && "Function templates must have prototypes"); TemplateParameterList *TemplateParams = FT2->getTemplateParameters(); - llvm::SmallVector<TemplateArgument, 4> Deduced; + llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(TemplateParams->size()); // C++0x [temp.deduct.partial]p3: @@ -2204,7 +2338,7 @@ Sema::getMoreSpecializedPartialSpecialization( // computation is slightly simpler than the general problem of function // template partial ordering, because class template partial specializations // are more constrained. We know that every template parameter is deduc - llvm::SmallVector<TemplateArgument, 4> Deduced; + llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; Sema::TemplateDeductionInfo Info(Context, Loc); // Determine whether PS1 is at least as specialized as PS2 @@ -2421,10 +2555,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; - case Type::Typename: + case Type::DependentName: if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, - cast<TypenameType>(T)->getQualifier(), + cast<DependentNameType>(T)->getQualifier(), OnlyDeduced, Depth, Used); break; @@ -2525,8 +2659,9 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, /// \brief Marks all of the template parameters that will be deduced by a /// call to the given function template. -void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl<bool> &Deduced) { +void +Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallVectorImpl<bool> &Deduced) { TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); Deduced.clear(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 0d6acd0..d21862b 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -394,7 +394,11 @@ void Sema::PrintInstantiationStack() { = cast<FunctionTemplateDecl>((Decl *)Active->Entity); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_explicit_template_arg_substitution_here) - << FnTmpl << Active->InstantiationRange; + << FnTmpl + << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), + Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange; break; } @@ -405,13 +409,21 @@ void Sema::PrintInstantiationStack() { Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_partial_spec_deduct_instantiation_here) << Context.getTypeDeclType(PartialSpec) + << getTemplateArgumentBindingsText( + PartialSpec->getTemplateParameters(), + Active->TemplateArgs, + Active->NumTemplateArgs) << Active->InstantiationRange; } else { FunctionTemplateDecl *FnTmpl = cast<FunctionTemplateDecl>((Decl *)Active->Entity); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_function_template_deduction_instantiation_here) - << FnTmpl << Active->InstantiationRange; + << FnTmpl + << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), + Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange; } break; @@ -677,8 +689,8 @@ TemplateInstantiator::RebuildElaboratedType(QualType T, if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) { SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) << Id - << CodeModificationHint::CreateReplacement(SourceRange(TagLocation), - TD->getKindName()); + << FixItHint::CreateReplacement(SourceRange(TagLocation), + TD->getKindName()); SemaRef.Diag(TD->getLocation(), diag::note_previous_use); } } @@ -745,101 +757,13 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, DeclarationName()); assert(!TargetType.isNull() && "type substitution failed for param type"); assert(!TargetType->isDependentType() && "param type still dependent"); - - if (VD->getDeclContext()->isRecord() && - (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) { - // If the value is a class member, we might have a pointer-to-member. - // Determine whether the non-type template template parameter is of - // pointer-to-member type. If so, we need to build an appropriate - // expression for a pointer-to-member, since a "normal" DeclRefExpr - // would refer to the member itself. - if (TargetType->isMemberPointerType()) { - QualType ClassType - = SemaRef.Context.getTypeDeclType( - cast<RecordDecl>(VD->getDeclContext())); - NestedNameSpecifier *Qualifier - = NestedNameSpecifier::Create(SemaRef.Context, 0, false, - ClassType.getTypePtr()); - CXXScopeSpec SS; - SS.setScopeRep(Qualifier); - OwningExprResult RefExpr - = SemaRef.BuildDeclRefExpr(VD, - VD->getType().getNonReferenceType(), - E->getLocation(), - &SS); - if (RefExpr.isInvalid()) - return SemaRef.ExprError(); - - RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(), - UnaryOperator::AddrOf, - move(RefExpr)); - assert(!RefExpr.isInvalid() && - SemaRef.Context.hasSameType(((Expr*) RefExpr.get())->getType(), - TargetType)); - return move(RefExpr); - } - } - - QualType T = VD->getType().getNonReferenceType(); - - if (TargetType->isPointerType()) { - // C++03 [temp.arg.nontype]p5: - // - For a non-type template-parameter of type pointer to - // object, qualification conversions and the array-to-pointer - // conversion are applied. - // - For a non-type template-parameter of type pointer to - // function, only the function-to-pointer conversion is - // applied. - - OwningExprResult RefExpr - = SemaRef.BuildDeclRefExpr(VD, T, E->getLocation()); - if (RefExpr.isInvalid()) - return SemaRef.ExprError(); - - // Decay functions and arrays. - Expr *RefE = (Expr *)RefExpr.get(); - SemaRef.DefaultFunctionArrayConversion(RefE); - if (RefE != RefExpr.get()) { - RefExpr.release(); - RefExpr = SemaRef.Owned(RefE); - } - - // Qualification conversions. - RefExpr.release(); - SemaRef.ImpCastExprToType(RefE, TargetType.getUnqualifiedType(), - CastExpr::CK_NoOp); - return SemaRef.Owned(RefE); - } - - // If the non-type template parameter has reference type, qualify the - // resulting declaration reference with the extra qualifiers on the - // type that the reference refers to. - if (const ReferenceType *TargetRef = TargetType->getAs<ReferenceType>()) - T = SemaRef.Context.getQualifiedType(T, - TargetRef->getPointeeType().getQualifiers()); - - return SemaRef.BuildDeclRefExpr(VD, T, E->getLocation()); + return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, + TargetType, + E->getLocation()); } - assert(Arg.getKind() == TemplateArgument::Integral); - QualType T = Arg.getIntegralType(); - if (T->isCharType() || T->isWideCharType()) - return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( - Arg.getAsIntegral()->getZExtValue(), - T->isWideCharType(), - T, - E->getSourceRange().getBegin())); - if (T->isBooleanType()) - return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( - Arg.getAsIntegral()->getBoolValue(), - T, - E->getSourceRange().getBegin())); - - assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); - return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( - *Arg.getAsIntegral(), - T, - E->getSourceRange().getBegin())); + return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg, + E->getSourceRange().getBegin()); } @@ -873,8 +797,11 @@ TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL, llvm::SmallVectorImpl<QualType> &PTypes, llvm::SmallVectorImpl<ParmVarDecl*> &PVars) { // Create a local instantiation scope for the parameters. - Sema::LocalInstantiationScope - Scope(SemaRef, SemaRef.CurrentInstantiationScope != 0); + // FIXME: When we implement the C++0x late-specified return type, + // we will need to move this scope out to the function type itself. + bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0); + Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope, + IsTemporaryScope); if (TreeTransform<TemplateInstantiator>:: TransformFunctionTypeParams(TL, PTypes, PVars)) @@ -1159,6 +1086,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, DeclContext *PreviousContext = CurContext; CurContext = Instantiation; + // If this is an instantiation of a local class, merge this local + // instantiation scope with the enclosing scope. Otherwise, every + // instantiation of a class has its own local instantiation scope. + bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod(); + Sema::LocalInstantiationScope Scope(*this, MergeWithParentScope); + // Start the definition of this instantiation. Instantiation->startDefinition(); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index dbe041c..3375ccc 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/DependentDiagnostic.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" @@ -285,17 +286,19 @@ static bool InstantiateInitializer(Sema &S, Expr *Init, } if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) { - if (InstantiateInitializationArguments(S, - Construct->getArgs(), - Construct->getNumArgs(), - TemplateArgs, - CommaLocs, NewArgs)) - return true; - - // FIXME: Fake locations! - LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart()); - RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back(); - return false; + if (!isa<CXXTemporaryObjectExpr>(Construct)) { + if (InstantiateInitializationArguments(S, + Construct->getArgs(), + Construct->getNumArgs(), + TemplateArgs, + CommaLocs, NewArgs)) + return true; + + // FIXME: Fake locations! + LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart()); + RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back(); + return false; + } } Sema::OwningExprResult Result = S.SubstExpr(Init, TemplateArgs); @@ -477,13 +480,17 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { // Handle friend type expressions by simply substituting template // parameters into the pattern type. - if (Type *Ty = D->getFriendType()) { - QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs, - D->getLocation(), DeclarationName()); - if (T.isNull()) return 0; + if (TypeSourceInfo *Ty = D->getFriendType()) { + TypeSourceInfo *InstTy = + SemaRef.SubstType(Ty, TemplateArgs, + D->getLocation(), DeclarationName()); + if (!InstTy) return 0; + + // This assertion is valid because the source type was necessarily + // an elaborated-type-specifier with a record tag. + assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType()); - assert(getLangOptions().CPlusPlus0x || T->isRecordType()); - FU = T.getTypePtr(); + FU = InstTy; // Handle everything else by appropriate substitution. } else { @@ -496,22 +503,12 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { Decl *NewND; // Hack to make this work almost well pending a rewrite. - if (ND->getDeclContext()->isRecord()) { - if (!ND->getDeclContext()->isDependentContext()) { - NewND = SemaRef.FindInstantiatedDecl(D->getLocation(), ND, - TemplateArgs); - } else { - // FIXME: Hack to avoid crashing when incorrectly trying to instantiate - // templated friend declarations. This doesn't produce a correct AST; - // however this is sufficient for some AST analysis. The real solution - // must be put in place during the pending rewrite. See PR5848. - return 0; - } - } else if (D->wasSpecialization()) { + if (D->wasSpecialization()) { // Totally egregious hack to work around PR5866 return 0; - } else + } else { NewND = Visit(ND); + } if (!NewND) return 0; FU = cast<NamedDecl>(NewND); @@ -638,6 +635,8 @@ namespace { } Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None); + // Create a local instantiation scope for this class template, which // will contain the instantiations of the template parameters. Sema::LocalInstantiationScope Scope(SemaRef); @@ -647,32 +646,106 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { return NULL; CXXRecordDecl *Pattern = D->getTemplatedDecl(); + + // Instantiate the qualifier. We have to do this first in case + // we're a friend declaration, because if we are then we need to put + // the new declaration in the appropriate context. + NestedNameSpecifier *Qualifier = Pattern->getQualifier(); + if (Qualifier) { + Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier, + Pattern->getQualifierRange(), + TemplateArgs); + if (!Qualifier) return 0; + } + + CXXRecordDecl *PrevDecl = 0; + ClassTemplateDecl *PrevClassTemplate = 0; + + // If this isn't a friend, then it's a member template, in which + // case we just want to build the instantiation in the + // specialization. If it is a friend, we want to build it in + // the appropriate context. + DeclContext *DC = Owner; + if (isFriend) { + if (Qualifier) { + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(Pattern->getQualifierRange()); + DC = SemaRef.computeDeclContext(SS); + if (!DC) return 0; + } else { + DC = SemaRef.FindInstantiatedContext(Pattern->getLocation(), + Pattern->getDeclContext(), + TemplateArgs); + } + + // Look for a previous declaration of the template in the owning + // context. + LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); + SemaRef.LookupQualifiedName(R, DC); + + if (R.isSingleResult()) { + PrevClassTemplate = R.getAsSingle<ClassTemplateDecl>(); + if (PrevClassTemplate) + PrevDecl = PrevClassTemplate->getTemplatedDecl(); + } + + if (!PrevClassTemplate && Qualifier) { + SemaRef.Diag(Pattern->getLocation(), diag::err_not_tag_in_scope) + << D->getTemplatedDecl()->getTagKind() << Pattern->getDeclName() << DC + << Pattern->getQualifierRange(); + return 0; + } + + if (PrevClassTemplate) { + TemplateParameterList *PrevParams + = PrevClassTemplate->getTemplateParameters(); + + // Make sure the parameter lists match. + if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, + /*Complain=*/true, + Sema::TPL_TemplateMatch)) + return 0; + + // Do some additional validation, then merge default arguments + // from the existing declarations. + if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, + Sema::TPC_ClassTemplate)) + return 0; + } + } + CXXRecordDecl *RecordInst - = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner, + = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), DC, Pattern->getLocation(), Pattern->getIdentifier(), - Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL, + Pattern->getTagKeywordLoc(), PrevDecl, /*DelayTypeCreation=*/true); - // Substitute the nested name specifier, if any. - if (SubstQualifier(Pattern, RecordInst)) - return 0; + if (Qualifier) + RecordInst->setQualifierInfo(Qualifier, Pattern->getQualifierRange()); ClassTemplateDecl *Inst - = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier(), InstParams, RecordInst, 0); + = ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(), + D->getIdentifier(), InstParams, RecordInst, + PrevClassTemplate); RecordInst->setDescribedClassTemplate(Inst); - if (D->getFriendObjectKind()) - Inst->setObjectOfFriendDecl(true); - else + if (isFriend) { + Inst->setObjectOfFriendDecl(PrevClassTemplate != 0); + // TODO: do we want to track the instantiation progeny of this + // friend target decl? + } else { Inst->setAccess(D->getAccess()); - Inst->setInstantiatedFromMemberTemplate(D); + Inst->setInstantiatedFromMemberTemplate(D); + } // Trigger creation of the type for the instantiation. SemaRef.Context.getInjectedClassNameType(RecordInst, Inst->getInjectedClassNameSpecialization(SemaRef.Context)); // Finish handling of friends. - if (Inst->getFriendObjectKind()) { + if (isFriend) { + DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false); return Inst; } @@ -762,16 +835,18 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { assert(InstTemplate && "VisitFunctionDecl/CXXMethodDecl didn't create a template!"); + bool isFriend = (InstTemplate->getFriendObjectKind() != Decl::FOK_None); + // Link the instantiation back to the pattern *unless* this is a // non-definition friend declaration. if (!InstTemplate->getInstantiatedFromMemberTemplate() && - !(InstTemplate->getFriendObjectKind() && - !D->getTemplatedDecl()->isThisDeclarationADefinition())) + !(isFriend && !D->getTemplatedDecl()->isThisDeclarationADefinition())) InstTemplate->setInstantiatedFromMemberTemplate(D); - // Add non-friends into the owner. - if (!InstTemplate->getFriendObjectKind()) + // Make declarations visible in the appropriate context. + if (!isFriend) Owner->addDecl(InstTemplate); + return InstTemplate; } @@ -843,6 +918,12 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return Info->Function; } + bool isFriend; + if (FunctionTemplate) + isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None); + else + isFriend = (D->getFriendObjectKind() != Decl::FOK_None); + bool MergeWithParentScope = (TemplateParams != 0) || !(isa<Decl>(Owner) && cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); @@ -855,14 +936,29 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return 0; QualType T = TInfo->getType(); + NestedNameSpecifier *Qualifier = D->getQualifier(); + if (Qualifier) { + Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier, + D->getQualifierRange(), + TemplateArgs); + if (!Qualifier) return 0; + } + // If we're instantiating a local function declaration, put the result // in the owner; otherwise we need to find the instantiated context. DeclContext *DC; if (D->getDeclContext()->isFunctionOrMethod()) DC = Owner; - else + else if (isFriend && Qualifier) { + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(D->getQualifierRange()); + DC = SemaRef.computeDeclContext(SS); + if (!DC) return 0; + } else { DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), TemplateArgs); + } FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), @@ -870,11 +966,16 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype()); - // Substitute the nested name specifier, if any. - if (SubstQualifier(D, Function)) - return 0; + if (Qualifier) + Function->setQualifierInfo(Qualifier, D->getQualifierRange()); - Function->setLexicalDeclContext(Owner); + DeclContext *LexicalDC = Owner; + if (!isFriend && D->isOutOfLine()) { + assert(D->getDeclContext()->isFileContext()); + LexicalDC = D->getDeclContext(); + } + + Function->setLexicalDeclContext(LexicalDC); // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) @@ -896,17 +997,29 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // which means substituting int for T, but leaving "f" as a friend function // template. // Build the function template itself. - FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner, + FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, DC, Function->getLocation(), Function->getDeclName(), TemplateParams, Function); Function->setDescribedFunctionTemplate(FunctionTemplate); - FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + + FunctionTemplate->setLexicalDeclContext(LexicalDC); + + if (isFriend && D->isThisDeclarationADefinition()) { + // TODO: should we remember this connection regardless of whether + // the friend declaration provided a body? + FunctionTemplate->setInstantiatedFromMemberTemplate( + D->getDescribedFunctionTemplate()); + } } else if (FunctionTemplate) { // Record this function template specialization. Function->setFunctionTemplateSpecialization(FunctionTemplate, &TemplateArgs.getInnermost(), InsertPos); + } else if (isFriend && D->isThisDeclarationADefinition()) { + // TODO: should we remember this connection regardless of whether + // the friend declaration provided a body? + Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } if (InitFunctionInstantiation(Function, D)) @@ -938,9 +1051,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // If the original function was part of a friend declaration, // inherit its namespace state and add it to the owner. - NamedDecl *FromFriendD - = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D; - if (FromFriendD->getFriendObjectKind()) { + if (isFriend) { NamedDecl *ToFriendD = 0; NamedDecl *PrevDecl; if (TemplateParams) { @@ -951,11 +1062,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrevDecl = Function->getPreviousDeclaration(); } ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL); - if (!Owner->isDependentContext() && !PrevDecl) - DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false); - - if (!TemplateParams) - Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); + DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false); } return Function; @@ -985,6 +1092,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return Info->Function; } + bool isFriend; + if (FunctionTemplate) + isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None); + else + isFriend = (D->getFriendObjectKind() != Decl::FOK_None); + bool MergeWithParentScope = (TemplateParams != 0) || !(isa<Decl>(Owner) && cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); @@ -997,8 +1110,31 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return 0; QualType T = TInfo->getType(); + NestedNameSpecifier *Qualifier = D->getQualifier(); + if (Qualifier) { + Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier, + D->getQualifierRange(), + TemplateArgs); + if (!Qualifier) return 0; + } + + DeclContext *DC = Owner; + if (isFriend) { + if (Qualifier) { + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(D->getQualifierRange()); + DC = SemaRef.computeDeclContext(SS); + } else { + DC = SemaRef.FindInstantiatedContext(D->getLocation(), + D->getDeclContext(), + TemplateArgs); + } + if (!DC) return 0; + } + // Build the instantiated method declaration. - CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); CXXMethodDecl *Method = 0; DeclarationName Name = D->getDeclName(); @@ -1035,9 +1171,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, D->isStatic(), D->isInlineSpecified()); } - // Substitute the nested name specifier, if any. - if (SubstQualifier(D, Method)) - return 0; + if (Qualifier) + Method->setQualifierInfo(Qualifier, D->getQualifierRange()); if (TemplateParams) { // Our resulting instantiation is actually a function template, since we @@ -1057,7 +1192,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->getLocation(), Method->getDeclName(), TemplateParams, Method); - if (D->isOutOfLine()) + if (isFriend) { + FunctionTemplate->setLexicalDeclContext(Owner); + FunctionTemplate->setObjectOfFriendDecl(true); + } else if (D->isOutOfLine()) FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (FunctionTemplate) { @@ -1065,7 +1203,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setFunctionTemplateSpecialization(FunctionTemplate, &TemplateArgs.getInnermost(), InsertPos); - } else { + } else if (!isFriend) { // Record that this is an instantiation of a member function. Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } @@ -1073,7 +1211,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // If we are instantiating a member function defined // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. - if (D->isOutOfLine()) + if (isFriend) { + Method->setLexicalDeclContext(Owner); + Method->setObjectOfFriendDecl(true); + } else if (D->isOutOfLine()) Method->setLexicalDeclContext(D->getLexicalDeclContext()); // Attach the parameters @@ -1087,8 +1228,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, LookupResult Previous(SemaRef, Name, SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); - if (!FunctionTemplate || TemplateParams) { - SemaRef.LookupQualifiedName(Previous, Owner); + if (!FunctionTemplate || TemplateParams || isFriend) { + SemaRef.LookupQualifiedName(Previous, Record); // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the @@ -1108,9 +1249,19 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setAccess(D->getAccess()); - if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) && - !Method->getFriendObjectKind()) - Owner->addDecl(Method); + if (FunctionTemplate) { + // If there's a function template, let our caller handle it. + } else if (Method->isInvalidDecl() && !Previous.empty()) { + // Don't hide a (potentially) valid declaration with an invalid one. + } else { + NamedDecl *DeclToAdd = (TemplateParams + ? cast<NamedDecl>(FunctionTemplate) + : Method); + if (isFriend) + Record->makeDeclVisibleInContext(DeclToAdd); + else + Owner->addDecl(DeclToAdd); + } return Method; } @@ -1694,8 +1845,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Proto->hasAnyExceptionSpec(), Exceptions.size(), Exceptions.data(), - Proto->getNoReturnAttr(), - Proto->getCallConv())); + Proto->getExtInfo())); } return false; @@ -1839,6 +1989,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), /*IsInstantiation=*/true); + PerformDependentDiagnostics(PatternDecl, TemplateArgs); + CurContext = PreviousContext; DeclGroupRef DG(Function); @@ -2475,3 +2627,17 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) { InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true); } } + +void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs) { + for (DeclContext::ddiag_iterator I = Pattern->ddiag_begin(), + E = Pattern->ddiag_end(); I != E; ++I) { + DependentDiagnostic *DD = *I; + + switch (DD->getKind()) { + case DependentDiagnostic::Access: + HandleDependentAccessCheck(*DD, TemplateArgs); + break; + } + } +} diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index a79853a..8278691 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -183,8 +183,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, if (DS.isEmpty()) { TheSema.Diag(DeclLoc, diag::ext_missing_declspec) << DS.getSourceRange() - << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(), - "int"); + << FixItHint::CreateInsertion(DS.getSourceRange().getBegin(), "int"); } } else if (!DS.hasTypeSpecifier()) { // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says: @@ -680,8 +679,11 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } if (ConstVal == 0) { - // GCC accepts zero sized static arrays. - Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) + // GCC accepts zero sized static arrays. We allow them when + // we're not in a SFINAE context. + Diag(ArraySize->getLocStart(), + isSFINAEContext()? diag::err_typecheck_zero_array_size + : diag::ext_typecheck_zero_array_size) << ArraySize->getSourceRange(); } T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); @@ -798,7 +800,8 @@ QualType Sema::BuildFunctionType(QualType T, return QualType(); return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, - Quals, false, false, 0, 0, false, CC_Default); + Quals, false, false, 0, 0, + FunctionType::ExtInfo()); } /// \brief Build a member pointer type \c T Class::*. @@ -1135,7 +1138,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, FTI.hasExceptionSpec, FTI.hasAnyExceptionSpec, Exceptions.size(), Exceptions.data(), - false, CC_Default); + FunctionType::ExtInfo()); } else if (FTI.isVariadic) { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" @@ -1152,7 +1155,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (!Overloadable) Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0, - false, false, 0, 0, false, CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); } else { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T); @@ -1228,7 +1232,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, FTI.hasExceptionSpec, FTI.hasAnyExceptionSpec, Exceptions.size(), Exceptions.data(), - false, CC_Default); + FunctionType::ExtInfo()); } // For GCC compatibility, we allow attributes that apply only to @@ -1257,7 +1261,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: - ClsType = Context.getTypenameType(NNSPrefix, NNS->getAsIdentifier()); + ClsType = Context.getDependentNameType(ETK_None, NNSPrefix, + NNS->getAsIdentifier()); break; case NestedNameSpecifier::Namespace: @@ -1326,7 +1331,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Strip the cv-quals from the type. T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), FnTy->getNumArgs(), FnTy->isVariadic(), 0, - false, false, 0, 0, false, CC_Default); + false, false, 0, 0, FunctionType::ExtInfo()); } } @@ -1734,6 +1739,30 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } + if (Attr.getKind() == AttributeList::AT_regparm) { + // The warning is emitted elsewhere + if (Attr.getNumArgs() != 1) { + return false; + } + + // Delay if this is not a function or pointer to block. + if (!Type->isFunctionPointerType() + && !Type->isBlockPointerType() + && !Type->isFunctionType()) + return true; + + // Otherwise we can process right away. + Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt NumParams(32); + + // The warning is emitted elsewhere + if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) + return false; + + Type = S.Context.getRegParmType(Type, NumParams.getZExtValue()); + return false; + } + // Otherwise, a calling convention. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; @@ -1863,6 +1892,7 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result, case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: case AttributeList::AT_stdcall: + case AttributeList::AT_regparm: // Don't process these on the DeclSpec. if (IsDeclSpec || ProcessFnAttr(S, Result, *AL)) @@ -1942,6 +1972,16 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, if (diag == 0) return true; + const TagType *Tag = 0; + if (const RecordType *Record = T->getAs<RecordType>()) + Tag = Record; + else if (const EnumType *Enum = T->getAs<EnumType>()) + Tag = Enum; + + // Avoid diagnosing invalid decls as incomplete. + if (Tag && Tag->getDecl()->isInvalidDecl()) + return true; + // We have an incomplete type. Produce a diagnostic. Diag(Loc, PD) << T; @@ -1950,13 +1990,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, Diag(Note.first, Note.second); // If the type was a forward declaration of a class/struct/union - // type, produce - const TagType *Tag = 0; - if (const RecordType *Record = T->getAs<RecordType>()) - Tag = Record; - else if (const EnumType *Enum = T->getAs<EnumType>()) - Tag = Enum; - + // type, produce a note. if (Tag && !Tag->getDecl()->isInvalidDecl()) Diag(Tag->getDecl()->getLocation(), Tag->isBeingDefined() ? diag::note_type_being_defined @@ -1966,6 +2000,18 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, return true; } +bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD) { + return RequireCompleteType(Loc, T, PD, + std::make_pair(SourceLocation(), PDiag(0))); +} + +bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, + unsigned DiagID) { + return RequireCompleteType(Loc, T, PDiag(DiagID), + std::make_pair(SourceLocation(), PDiag(0))); +} + /// \brief Retrieve a version of the type 'T' that is qualified by the /// nested-name-specifier contained in SS. QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) { @@ -1983,7 +2029,7 @@ QualType Sema::BuildTypeofExprType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization); + E = FixOverloadedFunctionReference(E, Specialization, Specialization); if (!E) return QualType(); } else { @@ -2003,7 +2049,7 @@ QualType Sema::BuildDecltypeType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization); + E = FixOverloadedFunctionReference(E, Specialization, Specialization); if (!E) return QualType(); } else { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index d6f3352..f9ffd3f 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -537,18 +537,22 @@ public: /// \brief Build a new typename type that refers to a template-id. /// - /// By default, builds a new TypenameType type from the nested-name-specifier + /// By default, builds a new DependentNameType type from the + /// nested-name-specifier /// and the given type. Subclasses may override this routine to provide /// different behavior. - QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) { + QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, QualType T) { if (NNS->isDependent()) { + // If the name is still dependent, just build a new dependent name type. CXXScopeSpec SS; SS.setScopeRep(NNS); if (!SemaRef.computeDeclContext(SS)) - return SemaRef.Context.getTypenameType(NNS, + return SemaRef.Context.getDependentNameType(Keyword, NNS, cast<TemplateSpecializationType>(T)); } - + + // FIXME: Handle elaborated-type-specifiers separately. return SemaRef.Context.getQualifiedNameType(NNS, T); } @@ -557,10 +561,80 @@ public: /// By default, performs semantic analysis when building the typename type /// (or qualified name type). Subclasses may override this routine to provide /// different behavior. - QualType RebuildTypenameType(NestedNameSpecifier *NNS, - const IdentifierInfo *Id, - SourceRange SR) { - return SemaRef.CheckTypenameType(NNS, *Id, SR); + QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Id, + SourceRange SR) { + CXXScopeSpec SS; + SS.setScopeRep(NNS); + + if (NNS->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); + } + + TagDecl::TagKind Kind = TagDecl::TK_enum; + switch (Keyword) { + case ETK_None: + // FIXME: Note the lack of the "typename" specifier! + // Fall through + case ETK_Typename: + return SemaRef.CheckTypenameType(NNS, *Id, SR); + + case ETK_Class: Kind = TagDecl::TK_class; break; + case ETK_Struct: Kind = TagDecl::TK_struct; break; + case ETK_Union: Kind = TagDecl::TK_union; break; + case ETK_Enum: Kind = TagDecl::TK_enum; break; + } + + // We had a dependent elaborated-type-specifier that as been transformed + // into a non-dependent elaborated-type-specifier. Find the tag we're + // referring to. + LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName); + DeclContext *DC = SemaRef.computeDeclContext(SS, false); + if (!DC) + return QualType(); + + TagDecl *Tag = 0; + SemaRef.LookupQualifiedName(Result, DC); + switch (Result.getResultKind()) { + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + break; + + case LookupResult::Found: + Tag = Result.getAsSingle<TagDecl>(); + break; + + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + llvm_unreachable("Tag lookup cannot find non-tags"); + return QualType(); + + case LookupResult::Ambiguous: + // Let the LookupResult structure handle ambiguities. + return QualType(); + } + + if (!Tag) { + // FIXME: Would be nice to highlight just the source range. + SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope) + << Kind << Id << DC; + return QualType(); + } + + // FIXME: Terrible location information + if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) { + SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id; + SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); + return QualType(); + } + + // Build the elaborated-type-specifier type. + QualType T = SemaRef.Context.getTypeDeclType(Tag); + T = SemaRef.Context.getQualifiedNameType(NNS, T); + return SemaRef.Context.getElaboratedType(T, Kind); } /// \brief Build a new nested-name-specifier given the prefix and an @@ -977,6 +1051,7 @@ public: SourceRange QualifierRange, SourceLocation MemberLoc, ValueDecl *Member, + NamedDecl *FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, NamedDecl *FirstQualifierInScope) { if (!Member->getDeclName()) { @@ -984,7 +1059,8 @@ public: assert(!Qualifier && "Can't have an unnamed field with a qualifier!"); Expr *BaseExpr = Base.takeAs<Expr>(); - if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier, Member)) + if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier, + FoundDecl, Member)) return getSema().ExprError(); MemberExpr *ME = @@ -1002,9 +1078,11 @@ public: QualType BaseType = ((Expr*) Base.get())->getType(); + // FIXME: this involves duplicating earlier analysis in a lot of + // cases; we should avoid this when possible. LookupResult R(getSema(), Member->getDeclName(), MemberLoc, Sema::LookupMemberName); - R.addDecl(Member); + R.addDecl(FoundDecl); R.resolveKind(); return getSema().BuildMemberReferenceExpr(move(Base), BaseType, @@ -2992,10 +3070,10 @@ TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB, } template<typename Derived> -QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, - TypenameTypeLoc TL, +QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB, + DependentNameTypeLoc TL, QualType ObjectType) { - TypenameType *T = TL.getTypePtr(); + DependentNameType *T = TL.getTypePtr(); /* FIXME: preserve source information better than this */ SourceRange SR(TL.getNameLoc()); @@ -3019,14 +3097,16 @@ QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, NewTemplateId == QualType(TemplateId, 0)) return QualType(T, 0); - Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + NewTemplateId); } else { - Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), SR); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + T->getIdentifier(), SR); } if (Result.isNull()) return QualType(); - TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); + DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -3868,10 +3948,21 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { if (!Member) return SemaRef.ExprError(); + NamedDecl *FoundDecl = E->getFoundDecl(); + if (FoundDecl == E->getMemberDecl()) { + FoundDecl = Member; + } else { + FoundDecl = cast_or_null<NamedDecl>( + getDerived().TransformDecl(E->getMemberLoc(), FoundDecl)); + if (!FoundDecl) + return SemaRef.ExprError(); + } + if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && Qualifier == E->getQualifier() && Member == E->getMemberDecl() && + FoundDecl == E->getFoundDecl() && !E->hasExplicitTemplateArgumentList()) { // Mark it referenced in the new context regardless. @@ -3908,6 +3999,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { E->getQualifierRange(), E->getMemberLoc(), Member, + FoundDecl, (E->hasExplicitTemplateArgumentList() ? &TransArgs : 0), FirstQualifierInScope); @@ -5118,7 +5210,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( !ArgumentChanged) { // FIXME: Instantiation-specific SemaRef.MarkDeclarationReferenced(E->getTypeBeginLoc(), Constructor); - return SemaRef.Owned(E->Retain()); + return SemaRef.MaybeBindToTemporary(E->Retain()); } // FIXME: Bogus location information |