diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2010-02-16 09:31:36 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2010-02-16 09:31:36 +0000 |
commit | ecb7e5c8afe929ee38155db94de6b084ec32a645 (patch) | |
tree | 53010172e19c77ea447bcd89e117cda052ab52e0 /lib | |
parent | 5044f5c816adfd5cba17f1adee1a10127296d0bf (diff) | |
download | src-test2-ecb7e5c8afe929ee38155db94de6b084ec32a645.tar.gz src-test2-ecb7e5c8afe929ee38155db94de6b084ec32a645.zip |
Notes
Diffstat (limited to 'lib')
226 files changed, 16999 insertions, 7512 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c1bc70989d4e..c23babb9a4a5 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -56,6 +56,10 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, } ASTContext::~ASTContext() { + // Release the DenseMaps associated with DeclContext objects. + // FIXME: Is this the ideal solution? + ReleaseDeclContextMaps(); + if (FreeMemory) { // Deallocate all the types. while (!Types.empty()) { @@ -533,12 +537,12 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { } } -/// getDeclAlignInBytes - Return a conservative estimate of the alignment of the +/// getDeclAlign - Return a conservative estimate of the alignment of the /// specified decl. Note that bitfields do not have a valid alignment, so /// this method will assert on them. /// If @p RefAsPointee, references are treated like their underlying type /// (for alignof), else they're treated like pointers (for CodeGen). -unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) { +CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) { unsigned Align = Target.getCharWidth(); if (const AlignedAttr* AA = D->getAttr<AlignedAttr>()) @@ -561,7 +565,7 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) { } } - return Align / Target.getCharWidth(); + return CharUnits::fromQuantity(Align / Target.getCharWidth()); } /// getTypeSize - Return the size of the specified type, in bits. This method @@ -820,6 +824,15 @@ CharUnits ASTContext::getTypeSizeInChars(const Type *T) { return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth()); } +/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in +/// characters. This method does not work on incomplete types. +CharUnits ASTContext::getTypeAlignInChars(QualType T) { + return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth()); +} +CharUnits ASTContext::getTypeAlignInChars(const Type *T) { + return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth()); +} + /// getPreferredTypeAlign - Return the "preferred" alignment of the specified /// type for the current target in bits. This can be different than the ABI /// alignment in cases where it is beneficial for performance to overalign @@ -904,12 +917,12 @@ void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, /// CollectInheritedProtocols - Collect all protocols in current class and /// those inherited by it. void ASTContext::CollectInheritedProtocols(const Decl *CDecl, - llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols) { + llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols) { if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) { for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), PE = OI->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); - Protocols.push_back(Proto); + Protocols.insert(Proto); for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); @@ -930,7 +943,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(), PE = OC->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); - Protocols.push_back(Proto); + Protocols.insert(Proto); for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); @@ -941,7 +954,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(), PE = OP->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); - Protocols.push_back(Proto); + Protocols.insert(Proto); for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); @@ -1088,7 +1101,7 @@ ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) { /// specified record (struct/union/class), which indicates its size and field /// position information. const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { - D = D->getDefinition(*this); + D = D->getDefinition(); assert(D && "Cannot get layout of forward declarations!"); // Look up this layout, if already laid out, return what we have. @@ -1105,7 +1118,7 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { } const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { - RD = cast<CXXRecordDecl>(RD->getDefinition(*this)); + RD = cast<CXXRecordDecl>(RD->getDefinition()); assert(RD && "Cannot get key function for forward declarations!"); const CXXMethodDecl *&Entry = KeyFunctions[RD]; @@ -1519,12 +1532,12 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy, void *InsertPos = 0; DependentSizedArrayType *Canon = 0; + llvm::FoldingSetNodeID ID; if (NumElts) { // Dependently-sized array types that do not have a specified // number of elements will have their sizes deduced from an // initializer. - llvm::FoldingSetNodeID ID; DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM, EltTypeQuals, NumElts); @@ -1545,8 +1558,13 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy, DependentSizedArrayType(*this, EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets); - if (NumElts) + if (NumElts) { + DependentSizedArrayType *CanonCheck + = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CanonCheck && "Dependent-sized canonical array type broken"); + (void)CanonCheck; DependentSizedArrayTypes.InsertNode(New, InsertPos); + } } else { QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts, ASM, EltTypeQuals, @@ -1596,7 +1614,8 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, /// getVectorType - Return the unique reference to a vector type of /// the specified element type and size. VectorType must be a built-in type. -QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { +QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, + bool IsAltiVec, bool IsPixel) { BuiltinType *baseType; baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr()); @@ -1604,7 +1623,8 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; - VectorType::Profile(ID, vecType, NumElts, Type::Vector); + VectorType::Profile(ID, vecType, NumElts, Type::Vector, + IsAltiVec, IsPixel); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(VTP, 0); @@ -1612,15 +1632,16 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { // If the element type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; - if (!vecType.isCanonical()) { - Canonical = getVectorType(getCanonicalType(vecType), NumElts); + if (!vecType.isCanonical() || IsAltiVec || IsPixel) { + Canonical = getVectorType(getCanonicalType(vecType), + NumElts, false, false); // Get the new insert position for the node we care about. VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } VectorType *New = new (*this, TypeAlignment) - VectorType(vecType, NumElts, Canonical); + VectorType(vecType, NumElts, Canonical, IsAltiVec, IsPixel); VectorTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); @@ -1636,7 +1657,7 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; - VectorType::Profile(ID, vecType, NumElts, Type::ExtVector); + VectorType::Profile(ID, vecType, NumElts, Type::ExtVector, false, false); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(VTP, 0); @@ -1681,6 +1702,11 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, New = new (*this, TypeAlignment) DependentSizedExtVectorType(*this, vecType, QualType(), SizeExpr, AttrLoc); + + DependentSizedExtVectorType *CanonCheck + = DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CanonCheck && "Dependent-sized ext_vector canonical type broken"); + (void)CanonCheck; DependentSizedExtVectorTypes.InsertNode(New, InsertPos); } else { QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, @@ -1694,12 +1720,6 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, return QualType(New, 0); } -static CallingConv getCanonicalCallingConv(CallingConv CC) { - if (CC == CC_C) - return CC_Default; - return CC; -} - /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, @@ -1707,7 +1727,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; - FunctionNoProtoType::Profile(ID, ResultTy, NoReturn); + FunctionNoProtoType::Profile(ID, ResultTy, NoReturn, CallConv); void *InsertPos = 0; if (FunctionNoProtoType *FT = @@ -1716,9 +1736,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, QualType Canonical; if (!ResultTy.isCanonical() || - getCanonicalCallingConv(CallConv) != CallConv) { + getCanonicalCallConv(CallConv) != CallConv) { Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn, - getCanonicalCallingConv(CallConv)); + getCanonicalCallConv(CallConv)); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -1727,7 +1747,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, } FunctionNoProtoType *New = new (*this, TypeAlignment) - FunctionNoProtoType(ResultTy, Canonical, NoReturn); + FunctionNoProtoType(ResultTy, Canonical, NoReturn, CallConv); Types.push_back(New); FunctionNoProtoTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1746,7 +1766,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, llvm::FoldingSetNodeID ID; FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - NumExs, ExArray, NoReturn); + NumExs, ExArray, NoReturn, CallConv); void *InsertPos = 0; if (FunctionProtoType *FTP = @@ -1762,7 +1782,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; - if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) { + if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) { llvm::SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -1772,7 +1792,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, CanonicalArgs.data(), NumArgs, isVariadic, TypeQuals, false, false, 0, 0, NoReturn, - getCanonicalCallingConv(CallConv)); + getCanonicalCallConv(CallConv)); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -1797,29 +1817,30 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, /// getTypeDeclType - Return the unique reference to the type for the /// specified type declaration. -QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { +QualType ASTContext::getTypeDeclType(const TypeDecl *Decl, + const TypeDecl* PrevDecl) { assert(Decl && "Passed null for Decl param"); if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl)) + if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl)) return getTypedefType(Typedef); else if (isa<TemplateTypeParmDecl>(Decl)) { assert(false && "Template type parameter types are always available."); - } else if (ObjCInterfaceDecl *ObjCInterface + } else if (const ObjCInterfaceDecl *ObjCInterface = dyn_cast<ObjCInterfaceDecl>(Decl)) return getObjCInterfaceType(ObjCInterface); - if (RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { + if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; else Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record); - } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { + } else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; else Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum); - } else if (UnresolvedUsingTypenameDecl *Using = + } else if (const UnresolvedUsingTypenameDecl *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using); } else @@ -1831,7 +1852,7 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { /// getTypedefType - Return the unique reference to the type for the /// specified typename decl. -QualType ASTContext::getTypedefType(TypedefDecl *Decl) { +QualType ASTContext::getTypedefType(const TypedefDecl *Decl) { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); QualType Canonical = getCanonicalType(Decl->getUnderlyingType()); @@ -1883,6 +1904,11 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack); TypeParm = new (*this, TypeAlignment) TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon); + + TemplateTypeParmType *TypeCheck + = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!TypeCheck && "Template type parameter canonical type broken"); + (void)TypeCheck; } else TypeParm = new (*this, TypeAlignment) TemplateTypeParmType(Depth, Index, ParameterPack); @@ -1976,8 +2002,16 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS, if (T) return QualType(T, 0); - T = new (*this) QualifiedNameType(NNS, NamedType, - getCanonicalType(NamedType)); + QualType Canon = NamedType; + if (!Canon.isCanonical()) { + Canon = getCanonicalType(NamedType); + QualifiedNameType *CheckT + = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Qualified name canonical type broken"); + (void)CheckT; + } + + T = new (*this) QualifiedNameType(NNS, NamedType, Canon); Types.push_back(T); QualifiedNameTypes.InsertNode(T, InsertPos); return QualType(T, 0); @@ -2015,6 +2049,15 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, QualType Canon) { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); + llvm::FoldingSetNodeID ID; + TypenameType::Profile(ID, NNS, TemplateId); + + void *InsertPos = 0; + TypenameType *T + = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + if (Canon.isNull()) { NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); QualType CanonType = getCanonicalType(QualType(TemplateId, 0)); @@ -2025,16 +2068,11 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, "Canonical type must also be a template specialization type"); Canon = getTypenameType(CanonNNS, CanonTemplateId); } - } - llvm::FoldingSetNodeID ID; - TypenameType::Profile(ID, NNS, TemplateId); - - void *InsertPos = 0; - TypenameType *T - = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); - if (T) - return QualType(T, 0); + TypenameType *CheckT + = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Typename canonical type is broken"); (void)CheckT; + } T = new (*this) TypenameType(NNS, TemplateId, Canon); Types.push_back(T); @@ -2053,7 +2091,12 @@ ASTContext::getElaboratedType(QualType UnderlyingType, if (T) return QualType(T, 0); - QualType Canon = getCanonicalType(UnderlyingType); + QualType Canon = UnderlyingType; + if (!Canon.isCanonical()) { + Canon = getCanonicalType(Canon); + ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Elaborated canonical type is broken"); (void)CheckT; + } T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon); Types.push_back(T); @@ -2125,10 +2168,14 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos); } - // No Match; - ObjCObjectPointerType *QType = new (*this, TypeAlignment) - ObjCObjectPointerType(*this, Canonical, InterfaceT, Protocols, - NumProtocols); + // No match. + unsigned Size = sizeof(ObjCObjectPointerType) + + NumProtocols * sizeof(ObjCProtocolDecl *); + void *Mem = Allocate(Size, TypeAlignment); + ObjCObjectPointerType *QType = new (Mem) ObjCObjectPointerType(Canonical, + InterfaceT, + Protocols, + NumProtocols); Types.push_back(QType); ObjCObjectPointerTypes.InsertNode(QType, InsertPos); @@ -2161,9 +2208,13 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos); } - ObjCInterfaceType *QType = new (*this, TypeAlignment) - ObjCInterfaceType(*this, Canonical, const_cast<ObjCInterfaceDecl*>(Decl), - Protocols, NumProtocols); + unsigned Size = sizeof(ObjCInterfaceType) + + NumProtocols * sizeof(ObjCProtocolDecl *); + void *Mem = Allocate(Size, TypeAlignment); + ObjCInterfaceType *QType = new (Mem) ObjCInterfaceType(Canonical, + const_cast<ObjCInterfaceDecl*>(Decl), + Protocols, + NumProtocols); Types.push_back(QType); ObjCInterfaceTypes.InsertNode(QType, InsertPos); @@ -2858,6 +2909,7 @@ QualType ASTContext::getCFConstantStringType() { CFConstantStringTypeDecl = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("NSConstantString")); + CFConstantStringTypeDecl->startDefinition(); QualType FieldTypes[4]; @@ -2880,7 +2932,7 @@ QualType ASTContext::getCFConstantStringType() { CFConstantStringTypeDecl->addDecl(Field); } - CFConstantStringTypeDecl->completeDefinition(*this); + CFConstantStringTypeDecl->completeDefinition(); } return getTagDeclType(CFConstantStringTypeDecl); @@ -2897,6 +2949,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { ObjCFastEnumerationStateTypeDecl = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("__objcFastEnumerationState")); + ObjCFastEnumerationStateTypeDecl->startDefinition(); QualType FieldTypes[] = { UnsignedLongTy, @@ -2916,7 +2969,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { ObjCFastEnumerationStateTypeDecl->addDecl(Field); } - ObjCFastEnumerationStateTypeDecl->completeDefinition(*this); + ObjCFastEnumerationStateTypeDecl->completeDefinition(); } return getTagDeclType(ObjCFastEnumerationStateTypeDecl); @@ -2930,6 +2983,7 @@ QualType ASTContext::getBlockDescriptorType() { // FIXME: Needs the FlagAppleBlock bit. T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("__block_descriptor")); + T->startDefinition(); QualType FieldTypes[] = { UnsignedLongTy, @@ -2952,7 +3006,7 @@ QualType ASTContext::getBlockDescriptorType() { T->addDecl(Field); } - T->completeDefinition(*this); + T->completeDefinition(); BlockDescriptorType = T; @@ -2973,6 +3027,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { // FIXME: Needs the FlagAppleBlock bit. T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("__block_descriptor_withcopydispose")); + T->startDefinition(); QualType FieldTypes[] = { UnsignedLongTy, @@ -2999,7 +3054,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { T->addDecl(Field); } - T->completeDefinition(*this); + T->completeDefinition(); BlockDescriptorExtendedType = T; @@ -3076,7 +3131,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { T->addDecl(Field); } - T->completeDefinition(*this); + T->completeDefinition(); return getPointerType(getTagDeclType(T)); } @@ -3093,6 +3148,7 @@ QualType ASTContext::getBlockParmType( RecordDecl *T; T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get(Name.str())); + T->startDefinition(); QualType FieldTypes[] = { getPointerType(VoidPtrTy), IntTy, @@ -3139,7 +3195,7 @@ QualType ASTContext::getBlockParmType( T->addDecl(Field); } - T->completeDefinition(*this); + T->completeDefinition(); return getPointerType(getTagDeclType(T)); } @@ -3786,6 +3842,7 @@ TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template) { + // FIXME: Canonicalization? llvm::FoldingSetNodeID ID; QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); @@ -3823,6 +3880,10 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, } else { TemplateName Canon = getDependentTemplateName(CanonNNS, Name); QTN = new (*this,4) DependentTemplateName(NNS, Name, Canon); + DependentTemplateName *CheckQTN = + DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckQTN && "Dependent type name canonicalization broken"); + (void)CheckQTN; } DependentTemplateNames.InsertNode(QTN, InsertPos); @@ -3841,8 +3902,8 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, DependentTemplateName::Profile(ID, NNS, Operator); void *InsertPos = 0; - DependentTemplateName *QTN = - DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + DependentTemplateName *QTN + = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); if (QTN) return TemplateName(QTN); @@ -3853,6 +3914,11 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, } else { TemplateName Canon = getDependentTemplateName(CanonNNS, Operator); QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon); + + DependentTemplateName *CheckQTN + = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckQTN && "Dependent template name canonicalization broken"); + (void)CheckQTN; } DependentTemplateNames.InsertNode(QTN, InsertPos); @@ -4123,8 +4189,8 @@ void getIntersectionOfProtocols(ASTContext &Context, if (LHSNumProtocols > 0) InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end()); else { - llvm::SmallVector<ObjCProtocolDecl *, 8> LHSInheritedProtocols; - Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols); + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols; + Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols); InheritedProtocolSet.insert(LHSInheritedProtocols.begin(), LHSInheritedProtocols.end()); } @@ -4137,13 +4203,13 @@ void getIntersectionOfProtocols(ASTContext &Context, IntersectionOfProtocols.push_back(RHSProtocols[i]); } else { - llvm::SmallVector<ObjCProtocolDecl *, 8> RHSInheritedProtocols; + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols; Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols); - // FIXME. This may cause duplication of protocols in the list, but should - // be harmless. - for (unsigned i = 0, len = RHSInheritedProtocols.size(); i < len; ++i) - if (InheritedProtocolSet.count(RHSInheritedProtocols[i])) - IntersectionOfProtocols.push_back(RHSInheritedProtocols[i]); + for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = + RHSInheritedProtocols.begin(), + E = RHSInheritedProtocols.end(); I != E; ++I) + if (InheritedProtocolSet.count((*I))) + IntersectionOfProtocols.push_back((*I)); } } @@ -4235,13 +4301,12 @@ bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { /// C99 6.2.7p1: Two types have compatible types if their types are the /// same. See 6.7.[2,3,5] for additional rules. bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) { + if (getLangOptions().CPlusPlus) + return hasSameType(LHS, RHS); + return !mergeTypes(LHS, RHS).isNull(); } -static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) { - return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc)); -} - QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { const FunctionType *lbase = lhs->getAs<FunctionType>(); const FunctionType *rbase = rhs->getAs<FunctionType>(); @@ -4266,7 +4331,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { CallingConv lcc = lbase->getCallConv(); CallingConv rcc = rbase->getCallConv(); // Compatible functions must have compatible calling conventions - if (!isSameCallingConvention(lcc, rcc)) + if (!isSameCallConv(lcc, rcc)) return QualType(); if (lproto && rproto) { // two C99 style function prototypes @@ -4303,7 +4368,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allRTypes) return rhs; return getFunctionType(retType, types.begin(), types.size(), lproto->isVariadic(), lproto->getTypeQuals(), - NoReturn, lcc); + false, false, 0, 0, NoReturn, lcc); } if (lproto) allRTypes = false; @@ -4321,6 +4386,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { unsigned proto_nargs = proto->getNumArgs(); for (unsigned i = 0; i < proto_nargs; ++i) { QualType argTy = proto->getArgType(i); + + // Look at the promotion type of enum types, since that is the type used + // to pass enum values. + if (const EnumType *Enum = argTy->getAs<EnumType>()) + argTy = Enum->getDecl()->getPromotionType(); + if (argTy->isPromotableIntegerType() || getCanonicalType(argTy).getUnqualifiedType() == FloatTy) return QualType(); @@ -4344,15 +4415,9 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { // designates the object or function denoted by the reference, and the // expression is an lvalue unless the reference is an rvalue reference and // the expression is a function call (possibly inside parentheses). - // FIXME: C++ shouldn't be going through here! The rules are different - // enough that they should be handled separately. - // FIXME: Merging of lvalue and rvalue references is incorrect. C++ *really* - // shouldn't be going through here! - if (const ReferenceType *RT = LHS->getAs<ReferenceType>()) - LHS = RT->getPointeeType(); - if (const ReferenceType *RT = RHS->getAs<ReferenceType>()) - RHS = RT->getPointeeType(); - + assert(!LHS->getAs<ReferenceType>() && "LHS is a reference type?"); + assert(!RHS->getAs<ReferenceType>() && "RHS is a reference type?"); + QualType LHSCan = getCanonicalType(LHS), RHSCan = getCanonicalType(RHS); @@ -4582,7 +4647,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) { // Turn <4 x signed int> -> <4 x unsigned int> if (const VectorType *VTy = T->getAs<VectorType>()) return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()), - VTy->getNumElements()); + VTy->getNumElements(), VTy->isAltiVec(), VTy->isPixel()); // For enums, we return the unsigned version of the base type. if (const EnumType *ETy = T->getAs<EnumType>()) @@ -4739,7 +4804,8 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, Str = End; QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); - Type = Context.getVectorType(ElementType, NumElements); + // FIXME: Don't know what to do about AltiVec. + Type = Context.getVectorType(ElementType, NumElements, false, false); break; } case 'X': { @@ -4784,6 +4850,9 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, case 'C': Type = Type.withConst(); break; + case 'D': + Type = Context.getVolatileType(Type); + break; } } diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp new file mode 100644 index 000000000000..7402b7dda4ec --- /dev/null +++ b/lib/AST/ASTDiagnostic.cpp @@ -0,0 +1,266 @@ +//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a diagnostic formatting hook for AST elements. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTDiagnostic.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Type.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +/// Determines whether we should have an a.k.a. clause when +/// pretty-printing a type. There are three main criteria: +/// +/// 1) Some types provide very minimal sugar that doesn't impede the +/// user's understanding --- for example, elaborated type +/// specifiers. If this is all the sugar we see, we don't want an +/// a.k.a. clause. +/// 2) Some types are technically sugared but are much more familiar +/// when seen in their sugared form --- for example, va_list, +/// vector types, and the magic Objective C types. We don't +/// want to desugar these, even if we do produce an a.k.a. clause. +/// 3) Some types may have already been desugared previously in this diagnostic. +/// if this is the case, doing another "aka" would just be clutter. +/// +static bool ShouldAKA(ASTContext &Context, QualType QT, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + QualType &DesugaredQT) { + QualType InputTy = QT; + + bool AKA = false; + QualifierCollector Qc; + + while (true) { + const Type *Ty = Qc.strip(QT); + + // Don't aka just because we saw an elaborated type... + if (isa<ElaboratedType>(Ty)) { + QT = cast<ElaboratedType>(Ty)->desugar(); + continue; + } + + // ...or a qualified name type... + if (isa<QualifiedNameType>(Ty)) { + QT = cast<QualifiedNameType>(Ty)->desugar(); + continue; + } + + // ...or a substituted template type parameter. + if (isa<SubstTemplateTypeParmType>(Ty)) { + QT = cast<SubstTemplateTypeParmType>(Ty)->desugar(); + continue; + } + + // Don't desugar template specializations. + if (isa<TemplateSpecializationType>(Ty)) + break; + + // Don't desugar magic Objective-C types. + if (QualType(Ty,0) == Context.getObjCIdType() || + QualType(Ty,0) == Context.getObjCClassType() || + QualType(Ty,0) == Context.getObjCSelType() || + QualType(Ty,0) == Context.getObjCProtoType()) + break; + + // Don't desugar va_list. + if (QualType(Ty,0) == Context.getBuiltinVaListType()) + break; + + // Otherwise, do a single-step desugar. + QualType Underlying; + bool IsSugar = false; + switch (Ty->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Base) +#define TYPE(Class, Base) \ +case Type::Class: { \ +const Class##Type *CTy = cast<Class##Type>(Ty); \ +if (CTy->isSugared()) { \ +IsSugar = true; \ +Underlying = CTy->desugar(); \ +} \ +break; \ +} +#include "clang/AST/TypeNodes.def" + } + + // If it wasn't sugared, we're done. + if (!IsSugar) + break; + + // If the desugared type is a vector type, we don't want to expand + // it, it will turn into an attribute mess. People want their "vec4". + if (isa<VectorType>(Underlying)) + break; + + // Don't desugar through the primary typedef of an anonymous type. + if (isa<TagType>(Underlying) && isa<TypedefType>(QT)) + if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() == + cast<TypedefType>(QT)->getDecl()) + break; + + // Otherwise, we're tearing through something opaque; note that + // we'll eventually need an a.k.a. clause and keep going. + AKA = true; + QT = Underlying; + continue; + } + + // If we never tore through opaque sugar, don't print aka. + if (!AKA) return false; + + // If we did, check to see if we already desugared this type in this + // diagnostic. If so, don't do it again. + for (unsigned i = 0; i != NumPrevArgs; ++i) { + // TODO: Handle ak_declcontext case. + if (PrevArgs[i].first == Diagnostic::ak_qualtype) { + void *Ptr = (void*)PrevArgs[i].second; + QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); + if (PrevTy == InputTy) + return false; + } + } + + DesugaredQT = Qc.apply(QT); + return true; +} + +/// \brief Convert the given type to a string suitable for printing as part of +/// a diagnostic. +/// +/// \param Context the context in which the type was allocated +/// \param Ty the type to print +static std::string +ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs) { + // FIXME: Playing with std::string is really slow. + std::string S = Ty.getAsString(Context.PrintingPolicy); + + // Consider producing an a.k.a. clause if removing all the direct + // sugar gives us something "significantly different". + + QualType DesugaredTy; + if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) { + S = "'"+S+"' (aka '"; + S += DesugaredTy.getAsString(Context.PrintingPolicy); + S += "')"; + return S; + } + + S = "'" + S + "'"; + return S; +} + +void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, + intptr_t Val, + const char *Modifier, + unsigned ModLen, + const char *Argument, + unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + llvm::SmallVectorImpl<char> &Output, + void *Cookie) { + ASTContext &Context = *static_cast<ASTContext*>(Cookie); + + std::string S; + bool NeedQuotes = true; + + switch (Kind) { + default: assert(0 && "unknown ArgumentKind"); + case Diagnostic::ak_qualtype: { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for QualType argument"); + + QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); + S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs); + NeedQuotes = false; + break; + } + case Diagnostic::ak_declarationname: { + DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); + S = N.getAsString(); + + if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0) + S = '+' + S; + else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) + && ArgLen==0) + S = '-' + S; + else + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for DeclarationName argument"); + break; + } + case Diagnostic::ak_nameddecl: { + bool Qualified; + if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) + Qualified = true; + else { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for NamedDecl* argument"); + Qualified = false; + } + reinterpret_cast<NamedDecl*>(Val)-> + getNameForDiagnostic(S, Context.PrintingPolicy, Qualified); + break; + } + case Diagnostic::ak_nestednamespec: { + llvm::raw_string_ostream OS(S); + reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS, + Context.PrintingPolicy); + NeedQuotes = false; + break; + } + case Diagnostic::ak_declcontext: { + DeclContext *DC = reinterpret_cast<DeclContext *> (Val); + assert(DC && "Should never have a null declaration context"); + + if (DC->isTranslationUnit()) { + // FIXME: Get these strings from some localized place + if (Context.getLangOptions().CPlusPlus) + S = "the global namespace"; + else + S = "the global scope"; + } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { + S = ConvertTypeToDiagnosticString(Context, + Context.getTypeDeclType(Type), + PrevArgs, NumPrevArgs); + } else { + // FIXME: Get these strings from some localized place + NamedDecl *ND = cast<NamedDecl>(DC); + if (isa<NamespaceDecl>(ND)) + S += "namespace "; + else if (isa<ObjCMethodDecl>(ND)) + S += "method "; + else if (isa<FunctionDecl>(ND)) + S += "function "; + + S += "'"; + ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); + S += "'"; + } + NeedQuotes = false; + break; + } + } + + if (NeedQuotes) + Output.push_back('\''); + + Output.append(S.begin(), S.end()); + + if (NeedQuotes) + Output.push_back('\''); +} diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp new file mode 100644 index 000000000000..dee0d2b342fc --- /dev/null +++ b/lib/AST/ASTImporter.cpp @@ -0,0 +1,2394 @@ +//===--- ASTImporter.cpp - Importing ASTs from other Contexts ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTImporter class which imports AST nodes from one +// context into another context. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTImporter.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include <deque> + +using namespace clang; + +namespace { + class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>, + public DeclVisitor<ASTNodeImporter, Decl *>, + public StmtVisitor<ASTNodeImporter, Stmt *> { + ASTImporter &Importer; + + public: + explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) { } + + using TypeVisitor<ASTNodeImporter, QualType>::Visit; + using DeclVisitor<ASTNodeImporter, Decl *>::Visit; + using StmtVisitor<ASTNodeImporter, Stmt *>::Visit; + + // Importing types + QualType VisitType(Type *T); + QualType VisitBuiltinType(BuiltinType *T); + QualType VisitComplexType(ComplexType *T); + QualType VisitPointerType(PointerType *T); + QualType VisitBlockPointerType(BlockPointerType *T); + QualType VisitLValueReferenceType(LValueReferenceType *T); + QualType VisitRValueReferenceType(RValueReferenceType *T); + QualType VisitMemberPointerType(MemberPointerType *T); + QualType VisitConstantArrayType(ConstantArrayType *T); + QualType VisitIncompleteArrayType(IncompleteArrayType *T); + QualType VisitVariableArrayType(VariableArrayType *T); + // FIXME: DependentSizedArrayType + // FIXME: DependentSizedExtVectorType + QualType VisitVectorType(VectorType *T); + QualType VisitExtVectorType(ExtVectorType *T); + QualType VisitFunctionNoProtoType(FunctionNoProtoType *T); + QualType VisitFunctionProtoType(FunctionProtoType *T); + // FIXME: UnresolvedUsingType + QualType VisitTypedefType(TypedefType *T); + QualType VisitTypeOfExprType(TypeOfExprType *T); + // FIXME: DependentTypeOfExprType + QualType VisitTypeOfType(TypeOfType *T); + QualType VisitDecltypeType(DecltypeType *T); + // FIXME: DependentDecltypeType + QualType VisitRecordType(RecordType *T); + QualType VisitEnumType(EnumType *T); + QualType VisitElaboratedType(ElaboratedType *T); + // FIXME: TemplateTypeParmType + // FIXME: SubstTemplateTypeParmType + // FIXME: TemplateSpecializationType + QualType VisitQualifiedNameType(QualifiedNameType *T); + // FIXME: TypenameType + QualType VisitObjCInterfaceType(ObjCInterfaceType *T); + QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T); + + // Importing declarations + bool ImportDeclParts(NamedDecl *D, DeclContext *&DC, + DeclContext *&LexicalDC, DeclarationName &Name, + SourceLocation &Loc); + bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord); + bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); + Decl *VisitDecl(Decl *D); + Decl *VisitTypedefDecl(TypedefDecl *D); + Decl *VisitEnumDecl(EnumDecl *D); + Decl *VisitRecordDecl(RecordDecl *D); + Decl *VisitEnumConstantDecl(EnumConstantDecl *D); + Decl *VisitFunctionDecl(FunctionDecl *D); + Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitVarDecl(VarDecl *D); + Decl *VisitParmVarDecl(ParmVarDecl *D); + Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + + // Importing statements + Stmt *VisitStmt(Stmt *S); + + // Importing expressions + Expr *VisitExpr(Expr *E); + Expr *VisitIntegerLiteral(IntegerLiteral *E); + Expr *VisitImplicitCastExpr(ImplicitCastExpr *E); + }; +} + +//---------------------------------------------------------------------------- +// Structural Equivalence +//---------------------------------------------------------------------------- + +namespace { + struct StructuralEquivalenceContext { + /// \brief AST contexts for which we are checking structural equivalence. + ASTContext &C1, &C2; + + /// \brief Diagnostic object used to emit diagnostics. + Diagnostic &Diags; + + /// \brief The set of "tentative" equivalences between two canonical + /// declarations, mapping from a declaration in the first context to the + /// declaration in the second context that we believe to be equivalent. + llvm::DenseMap<Decl *, Decl *> TentativeEquivalences; + + /// \brief Queue of declarations in the first context whose equivalence + /// with a declaration in the second context still needs to be verified. + std::deque<Decl *> DeclsToCheck; + + /// \brief Declaration (from, to) pairs that are known not to be equivalent + /// (which we have already complained about). + llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls; + + /// \brief Whether we're being strict about the spelling of types when + /// unifying two types. + bool StrictTypeSpelling; + + StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2, + Diagnostic &Diags, + llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls, + bool StrictTypeSpelling = false) + : C1(C1), C2(C2), Diags(Diags), NonEquivalentDecls(NonEquivalentDecls), + StrictTypeSpelling(StrictTypeSpelling) { } + + /// \brief Determine whether the two declarations are structurally + /// equivalent. + bool IsStructurallyEquivalent(Decl *D1, Decl *D2); + + /// \brief Determine whether the two types are structurally equivalent. + bool IsStructurallyEquivalent(QualType T1, QualType T2); + + private: + /// \brief Finish checking all of the structural equivalences. + /// + /// \returns true if an error occurred, false otherwise. + bool Finish(); + + public: + DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(FullSourceLoc(Loc, C1.getSourceManager()), DiagID); + } + + DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(FullSourceLoc(Loc, C2.getSourceManager()), DiagID); + } + }; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2); + +/// \brief Determine if two APInts have the same value, after zero-extending +/// one of them (if needed!) to ensure that the bit-widths match. +static bool IsSameValue(const llvm::APInt &I1, const llvm::APInt &I2) { + if (I1.getBitWidth() == I2.getBitWidth()) + return I1 == I2; + + if (I1.getBitWidth() > I2.getBitWidth()) + return I1 == llvm::APInt(I2).zext(I1.getBitWidth()); + + return llvm::APInt(I1).zext(I2.getBitWidth()) == I2; +} + +/// \brief Determine if two APSInts have the same value, zero- or sign-extending +/// as needed. +static bool IsSameValue(const llvm::APSInt &I1, const llvm::APSInt &I2) { + if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned()) + return I1 == I2; + + // Check for a bit-width mismatch. + if (I1.getBitWidth() > I2.getBitWidth()) + return IsSameValue(I1, llvm::APSInt(I2).extend(I1.getBitWidth())); + else if (I2.getBitWidth() > I1.getBitWidth()) + return IsSameValue(llvm::APSInt(I1).extend(I2.getBitWidth()), I2); + + // We have a signedness mismatch. Turn the signed value into an unsigned + // value. + if (I1.isSigned()) { + if (I1.isNegative()) + return false; + + return llvm::APSInt(I1, true) == I2; + } + + if (I2.isNegative()) + return false; + + return I1 == llvm::APSInt(I2, true); +} + +/// \brief Determine structural equivalence of two expressions. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Expr *E1, Expr *E2) { + if (!E1 || !E2) + return E1 == E2; + + // FIXME: Actually perform a structural comparison! + return true; +} + +/// \brief Determine whether two identifiers are equivalent. +static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, + const IdentifierInfo *Name2) { + if (!Name1 || !Name2) + return Name1 == Name2; + + return Name1->getName() == Name2->getName(); +} + +/// \brief Determine whether two nested-name-specifiers are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NestedNameSpecifier *NNS1, + NestedNameSpecifier *NNS2) { + // FIXME: Implement! + return true; +} + +/// \brief Determine whether two template arguments are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgument &Arg1, + const TemplateArgument &Arg2) { + // FIXME: Implement! + return true; +} + +/// \brief Determine structural equivalence for the common part of array +/// types. +static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, + const ArrayType *Array1, + const ArrayType *Array2) { + if (!IsStructurallyEquivalent(Context, + Array1->getElementType(), + Array2->getElementType())) + return false; + if (Array1->getSizeModifier() != Array2->getSizeModifier()) + return false; + if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers()) + return false; + + return true; +} + +/// \brief Determine structural equivalence of two types. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2) { + if (T1.isNull() || T2.isNull()) + return T1.isNull() && T2.isNull(); + + if (!Context.StrictTypeSpelling) { + // We aren't being strict about token-to-token equivalence of types, + // so map down to the canonical type. + T1 = Context.C1.getCanonicalType(T1); + T2 = Context.C2.getCanonicalType(T2); + } + + if (T1.getQualifiers() != T2.getQualifiers()) + return false; + + Type::TypeClass TC = T1->getTypeClass(); + + if (T1->getTypeClass() != T2->getTypeClass()) { + // Compare function types with prototypes vs. without prototypes as if + // both did not have prototypes. + if (T1->getTypeClass() == Type::FunctionProto && + T2->getTypeClass() == Type::FunctionNoProto) + TC = Type::FunctionNoProto; + else if (T1->getTypeClass() == Type::FunctionNoProto && + T2->getTypeClass() == Type::FunctionProto) + TC = Type::FunctionNoProto; + else + return false; + } + + switch (TC) { + case Type::Builtin: + // FIXME: Deal with Char_S/Char_U. + if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind()) + return false; + break; + + case Type::Complex: + if (!IsStructurallyEquivalent(Context, + cast<ComplexType>(T1)->getElementType(), + cast<ComplexType>(T2)->getElementType())) + return false; + break; + + case Type::Pointer: + if (!IsStructurallyEquivalent(Context, + cast<PointerType>(T1)->getPointeeType(), + cast<PointerType>(T2)->getPointeeType())) + return false; + break; + + case Type::BlockPointer: + if (!IsStructurallyEquivalent(Context, + cast<BlockPointerType>(T1)->getPointeeType(), + cast<BlockPointerType>(T2)->getPointeeType())) + return false; + break; + + case Type::LValueReference: + case Type::RValueReference: { + const ReferenceType *Ref1 = cast<ReferenceType>(T1); + const ReferenceType *Ref2 = cast<ReferenceType>(T2); + if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue()) + return false; + if (Ref1->isInnerRef() != Ref2->isInnerRef()) + return false; + if (!IsStructurallyEquivalent(Context, + Ref1->getPointeeTypeAsWritten(), + Ref2->getPointeeTypeAsWritten())) + return false; + break; + } + + case Type::MemberPointer: { + const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1); + const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2); + if (!IsStructurallyEquivalent(Context, + MemPtr1->getPointeeType(), + MemPtr2->getPointeeType())) + return false; + if (!IsStructurallyEquivalent(Context, + QualType(MemPtr1->getClass(), 0), + QualType(MemPtr2->getClass(), 0))) + return false; + break; + } + + case Type::ConstantArray: { + const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1); + const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2); + if (!IsSameValue(Array1->getSize(), Array2->getSize())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + break; + } + + case Type::IncompleteArray: + if (!IsArrayStructurallyEquivalent(Context, + cast<ArrayType>(T1), + cast<ArrayType>(T2))) + return false; + break; + + case Type::VariableArray: { + const VariableArrayType *Array1 = cast<VariableArrayType>(T1); + const VariableArrayType *Array2 = cast<VariableArrayType>(T2); + if (!IsStructurallyEquivalent(Context, + Array1->getSizeExpr(), Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedArray: { + const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1); + const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2); + if (!IsStructurallyEquivalent(Context, + Array1->getSizeExpr(), Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedExtVector: { + const DependentSizedExtVectorType *Vec1 + = cast<DependentSizedExtVectorType>(T1); + const DependentSizedExtVectorType *Vec2 + = cast<DependentSizedExtVectorType>(T2); + if (!IsStructurallyEquivalent(Context, + Vec1->getSizeExpr(), Vec2->getSizeExpr())) + return false; + if (!IsStructurallyEquivalent(Context, + Vec1->getElementType(), + Vec2->getElementType())) + return false; + break; + } + + case Type::Vector: + case Type::ExtVector: { + const VectorType *Vec1 = cast<VectorType>(T1); + const VectorType *Vec2 = cast<VectorType>(T2); + if (!IsStructurallyEquivalent(Context, + Vec1->getElementType(), + Vec2->getElementType())) + return false; + if (Vec1->getNumElements() != Vec2->getNumElements()) + return false; + if (Vec1->isAltiVec() != Vec2->isAltiVec()) + return false; + if (Vec1->isPixel() != Vec2->isPixel()) + return false; + } + + case Type::FunctionProto: { + const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1); + const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2); + if (Proto1->getNumArgs() != Proto2->getNumArgs()) + return false; + for (unsigned I = 0, N = Proto1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Proto1->getArgType(I), + Proto2->getArgType(I))) + return false; + } + if (Proto1->isVariadic() != Proto2->isVariadic()) + return false; + if (Proto1->hasExceptionSpec() != Proto2->hasExceptionSpec()) + return false; + if (Proto1->hasAnyExceptionSpec() != Proto2->hasAnyExceptionSpec()) + return false; + if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + return false; + for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Proto1->getExceptionType(I), + Proto2->getExceptionType(I))) + return false; + } + if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) + return false; + + // Fall through to check the bits common with FunctionNoProtoType. + } + + case Type::FunctionNoProto: { + const FunctionType *Function1 = cast<FunctionType>(T1); + const FunctionType *Function2 = cast<FunctionType>(T2); + if (!IsStructurallyEquivalent(Context, + Function1->getResultType(), + Function2->getResultType())) + return false; + if (Function1->getNoReturnAttr() != Function2->getNoReturnAttr()) + return false; + if (Function1->getCallConv() != Function2->getCallConv()) + return false; + break; + } + + case Type::UnresolvedUsing: + if (!IsStructurallyEquivalent(Context, + cast<UnresolvedUsingType>(T1)->getDecl(), + cast<UnresolvedUsingType>(T2)->getDecl())) + return false; + + break; + + case Type::Typedef: + if (!IsStructurallyEquivalent(Context, + cast<TypedefType>(T1)->getDecl(), + cast<TypedefType>(T2)->getDecl())) + return false; + break; + + case Type::TypeOfExpr: + if (!IsStructurallyEquivalent(Context, + cast<TypeOfExprType>(T1)->getUnderlyingExpr(), + cast<TypeOfExprType>(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::TypeOf: + if (!IsStructurallyEquivalent(Context, + cast<TypeOfType>(T1)->getUnderlyingType(), + cast<TypeOfType>(T2)->getUnderlyingType())) + return false; + break; + + case Type::Decltype: + if (!IsStructurallyEquivalent(Context, + cast<DecltypeType>(T1)->getUnderlyingExpr(), + cast<DecltypeType>(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::Record: + case Type::Enum: + if (!IsStructurallyEquivalent(Context, + cast<TagType>(T1)->getDecl(), + cast<TagType>(T2)->getDecl())) + return false; + break; + + case Type::Elaborated: { + const ElaboratedType *Elab1 = cast<ElaboratedType>(T1); + const ElaboratedType *Elab2 = cast<ElaboratedType>(T2); + if (Elab1->getTagKind() != Elab2->getTagKind()) + return false; + if (!IsStructurallyEquivalent(Context, + Elab1->getUnderlyingType(), + Elab2->getUnderlyingType())) + return false; + break; + } + + case Type::TemplateTypeParm: { + const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1); + const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2); + if (Parm1->getDepth() != Parm2->getDepth()) + return false; + if (Parm1->getIndex() != Parm2->getIndex()) + return false; + if (Parm1->isParameterPack() != Parm2->isParameterPack()) + return false; + + // Names of template type parameters are never significant. + break; + } + + case Type::SubstTemplateTypeParm: { + const SubstTemplateTypeParmType *Subst1 + = cast<SubstTemplateTypeParmType>(T1); + const SubstTemplateTypeParmType *Subst2 + = cast<SubstTemplateTypeParmType>(T2); + if (!IsStructurallyEquivalent(Context, + QualType(Subst1->getReplacedParameter(), 0), + QualType(Subst2->getReplacedParameter(), 0))) + return false; + if (!IsStructurallyEquivalent(Context, + Subst1->getReplacementType(), + Subst2->getReplacementType())) + return false; + break; + } + + case Type::TemplateSpecialization: { + const TemplateSpecializationType *Spec1 + = cast<TemplateSpecializationType>(T1); + const TemplateSpecializationType *Spec2 + = cast<TemplateSpecializationType>(T2); + if (!IsStructurallyEquivalent(Context, + Spec1->getTemplateName(), + Spec2->getTemplateName())) + return false; + if (Spec1->getNumArgs() != Spec2->getNumArgs()) + return false; + for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Spec1->getArg(I), Spec2->getArg(I))) + return false; + } + break; + } + + case Type::QualifiedName: { + const QualifiedNameType *Qual1 = cast<QualifiedNameType>(T1); + const QualifiedNameType *Qual2 = cast<QualifiedNameType>(T2); + if (!IsStructurallyEquivalent(Context, + Qual1->getQualifier(), + Qual2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, + Qual1->getNamedType(), + Qual2->getNamedType())) + return false; + break; + } + + case Type::Typename: { + const TypenameType *Typename1 = cast<TypenameType>(T1); + const TypenameType *Typename2 = cast<TypenameType>(T2); + if (!IsStructurallyEquivalent(Context, + Typename1->getQualifier(), + Typename2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Typename1->getIdentifier(), + Typename2->getIdentifier())) + return false; + if (!IsStructurallyEquivalent(Context, + QualType(Typename1->getTemplateId(), 0), + QualType(Typename2->getTemplateId(), 0))) + return false; + + break; + } + + case Type::ObjCInterface: { + const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1); + const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2); + if (!IsStructurallyEquivalent(Context, + Iface1->getDecl(), Iface2->getDecl())) + return false; + if (Iface1->getNumProtocols() != Iface2->getNumProtocols()) + return false; + for (unsigned I = 0, N = Iface1->getNumProtocols(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Iface1->getProtocol(I), + Iface2->getProtocol(I))) + return false; + } + break; + } + + case Type::ObjCObjectPointer: { + const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1); + const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2); + if (!IsStructurallyEquivalent(Context, + Ptr1->getPointeeType(), + Ptr2->getPointeeType())) + return false; + if (Ptr1->getNumProtocols() != Ptr2->getNumProtocols()) + return false; + for (unsigned I = 0, N = Ptr1->getNumProtocols(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Ptr1->getProtocol(I), + Ptr2->getProtocol(I))) + return false; + } + break; + } + + } // end switch + + return true; +} + +/// \brief Determine structural equivalence of two records. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + RecordDecl *D1, RecordDecl *D2) { + if (D1->isUnion() != D2->isUnion()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) + << D1->getDeclName() << (unsigned)D1->getTagKind(); + return false; + } + + // Compare the definitions of these two records. If either or both are + // incomplete, we assume that they are equivalent. + D1 = D1->getDefinition(); + D2 = D2->getDefinition(); + if (!D1 || !D2) + return true; + + if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) { + if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { + if (D1CXX->getNumBases() != D2CXX->getNumBases()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) + << D2CXX->getNumBases(); + Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) + << D1CXX->getNumBases(); + return false; + } + + // Check the base classes. + for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(), + BaseEnd1 = D1CXX->bases_end(), + Base2 = D2CXX->bases_begin(); + Base1 != BaseEnd1; + ++Base1, ++Base2) { + if (!IsStructurallyEquivalent(Context, + Base1->getType(), Base2->getType())) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getSourceRange().getBegin(), diag::note_odr_base) + << Base2->getType() + << Base2->getSourceRange(); + Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + return false; + } + + // Check virtual vs. non-virtual inheritance mismatch. + if (Base1->isVirtual() != Base2->isVirtual()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getSourceRange().getBegin(), + diag::note_odr_virtual_base) + << Base2->isVirtual() << Base2->getSourceRange(); + Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base) + << Base1->isVirtual() + << Base1->getSourceRange(); + return false; + } + } + } else if (D1CXX->getNumBases() > 0) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); + Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); + return false; + } + } + + // Check the fields for consistency. + CXXRecordDecl::field_iterator Field2 = D2->field_begin(), + Field2End = D2->field_end(); + for (CXXRecordDecl::field_iterator Field1 = D1->field_begin(), + Field1End = D1->field_end(); + Field1 != Field1End; + ++Field1, ++Field2) { + if (Field2 == Field2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); + return false; + } + + if (!IsStructurallyEquivalent(Context, + Field1->getType(), Field2->getType())) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + return false; + } + + if (Field1->isBitField() != Field2->isBitField()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + if (Field1->isBitField()) { + llvm::APSInt Bits; + Field1->getBitWidth()->isIntegerConstantExpr(Bits, Context.C1); + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Bits.toString(10, false); + Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) + << Field2->getDeclName(); + } else { + llvm::APSInt Bits; + Field2->getBitWidth()->isIntegerConstantExpr(Bits, Context.C2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Bits.toString(10, false); + Context.Diag1(Field1->getLocation(), + diag::note_odr_not_bit_field) + << Field1->getDeclName(); + } + return false; + } + + if (Field1->isBitField()) { + // Make sure that the bit-fields are the same length. + llvm::APSInt Bits1, Bits2; + if (!Field1->getBitWidth()->isIntegerConstantExpr(Bits1, Context.C1)) + return false; + if (!Field2->getBitWidth()->isIntegerConstantExpr(Bits2, Context.C2)) + return false; + + if (!IsSameValue(Bits1, Bits2)) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Bits2.toString(10, false); + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Bits1.toString(10, false); + return false; + } + } + } + + if (Field2 != Field2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); + return false; + } + + return true; +} + +/// \brief Determine structural equivalence of two enums. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + EnumDecl *D1, EnumDecl *D2) { + EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(), + EC2End = D2->enumerator_end(); + for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(), + EC1End = D1->enumerator_end(); + EC1 != EC1End; ++EC1, ++EC2) { + if (EC2 == EC2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); + return false; + } + + llvm::APSInt Val1 = EC1->getInitVal(); + llvm::APSInt Val2 = EC2->getInitVal(); + if (!IsSameValue(Val1, Val2) || + !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() + << EC2->getInitVal().toString(10); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + return false; + } + } + + if (EC2 != EC2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() + << EC2->getInitVal().toString(10); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); + return false; + } + + return true; +} + +/// \brief Determine structural equivalence of two declarations. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2) { + // FIXME: Check for known structural equivalences via a callback of some sort. + + // Check whether we already know that these two declarations are not + // structurally equivalent. + if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(), + D2->getCanonicalDecl()))) + return false; + + // Determine whether we've already produced a tentative equivalence for D1. + Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()]; + if (EquivToD1) + return EquivToD1 == D2->getCanonicalDecl(); + + // Produce a tentative equivalence D1 <-> D2, which will be checked later. + EquivToD1 = D2->getCanonicalDecl(); + Context.DeclsToCheck.push_back(D1->getCanonicalDecl()); + return true; +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1, + Decl *D2) { + if (!::IsStructurallyEquivalent(*this, D1, D2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1, + QualType T2) { + if (!::IsStructurallyEquivalent(*this, T1, T2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::Finish() { + while (!DeclsToCheck.empty()) { + // Check the next declaration. + Decl *D1 = DeclsToCheck.front(); + DeclsToCheck.pop_front(); + + Decl *D2 = TentativeEquivalences[D1]; + assert(D2 && "Unrecorded tentative equivalence?"); + + bool Equivalent = true; + + // FIXME: Switch on all declaration kinds. For now, we're just going to + // check the obvious ones. + if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) { + if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) { + // Check for equivalent structure names. + IdentifierInfo *Name1 = Record1->getIdentifier(); + if (!Name1 && Record1->getTypedefForAnonDecl()) + Name1 = Record1->getTypedefForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Record2->getIdentifier(); + if (!Name2 && Record2->getTypedefForAnonDecl()) + Name2 = Record2->getTypedefForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Record1, Record2)) + Equivalent = false; + } else { + // Record/non-record mismatch. + Equivalent = false; + } + } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) { + if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) { + // Check for equivalent enum names. + IdentifierInfo *Name1 = Enum1->getIdentifier(); + if (!Name1 && Enum1->getTypedefForAnonDecl()) + Name1 = Enum1->getTypedefForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Enum2->getIdentifier(); + if (!Name2 && Enum2->getTypedefForAnonDecl()) + Name2 = Enum2->getTypedefForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Enum1, Enum2)) + Equivalent = false; + } else { + // Enum/non-enum mismatch + Equivalent = false; + } + } else if (TypedefDecl *Typedef1 = dyn_cast<TypedefDecl>(D1)) { + if (TypedefDecl *Typedef2 = dyn_cast<TypedefDecl>(D2)) { + if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), + Typedef2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, + Typedef1->getUnderlyingType(), + Typedef2->getUnderlyingType())) + Equivalent = false; + } else { + // Typedef/non-typedef mismatch. + Equivalent = false; + } + } + + if (!Equivalent) { + // Note that these two declarations are not equivalent (and we already + // know about it). + NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(), + D2->getCanonicalDecl())); + return true; + } + // FIXME: Check other declaration kinds! + } + + return false; +} + +//---------------------------------------------------------------------------- +// Import Types +//---------------------------------------------------------------------------- + +QualType ASTNodeImporter::VisitType(Type *T) { + Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node) + << T->getTypeClassName(); + return QualType(); +} + +QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) { + switch (T->getKind()) { + case BuiltinType::Void: return Importer.getToContext().VoidTy; + case BuiltinType::Bool: return Importer.getToContext().BoolTy; + + case BuiltinType::Char_U: + // The context we're importing from has an unsigned 'char'. If we're + // importing into a context with a signed 'char', translate to + // 'unsigned char' instead. + if (Importer.getToContext().getLangOptions().CharIsSigned) + return Importer.getToContext().UnsignedCharTy; + + return Importer.getToContext().CharTy; + + case BuiltinType::UChar: return Importer.getToContext().UnsignedCharTy; + + case BuiltinType::Char16: + // FIXME: Make sure that the "to" context supports C++! + return Importer.getToContext().Char16Ty; + + case BuiltinType::Char32: + // FIXME: Make sure that the "to" context supports C++! + return Importer.getToContext().Char32Ty; + + case BuiltinType::UShort: return Importer.getToContext().UnsignedShortTy; + case BuiltinType::UInt: return Importer.getToContext().UnsignedIntTy; + case BuiltinType::ULong: return Importer.getToContext().UnsignedLongTy; + case BuiltinType::ULongLong: + return Importer.getToContext().UnsignedLongLongTy; + case BuiltinType::UInt128: return Importer.getToContext().UnsignedInt128Ty; + + case BuiltinType::Char_S: + // The context we're importing from has an unsigned 'char'. If we're + // importing into a context with a signed 'char', translate to + // 'unsigned char' instead. + if (!Importer.getToContext().getLangOptions().CharIsSigned) + return Importer.getToContext().SignedCharTy; + + return Importer.getToContext().CharTy; + + case BuiltinType::SChar: return Importer.getToContext().SignedCharTy; + case BuiltinType::WChar: + // FIXME: If not in C++, shall we translate to the C equivalent of + // wchar_t? + return Importer.getToContext().WCharTy; + + case BuiltinType::Short : return Importer.getToContext().ShortTy; + case BuiltinType::Int : return Importer.getToContext().IntTy; + case BuiltinType::Long : return Importer.getToContext().LongTy; + case BuiltinType::LongLong : return Importer.getToContext().LongLongTy; + case BuiltinType::Int128 : return Importer.getToContext().Int128Ty; + case BuiltinType::Float: return Importer.getToContext().FloatTy; + case BuiltinType::Double: return Importer.getToContext().DoubleTy; + case BuiltinType::LongDouble: return Importer.getToContext().LongDoubleTy; + + case BuiltinType::NullPtr: + // FIXME: Make sure that the "to" context supports C++0x! + return Importer.getToContext().NullPtrTy; + + case BuiltinType::Overload: return Importer.getToContext().OverloadTy; + case BuiltinType::Dependent: return Importer.getToContext().DependentTy; + case BuiltinType::UndeducedAuto: + // FIXME: Make sure that the "to" context supports C++0x! + return Importer.getToContext().UndeducedAutoTy; + + case BuiltinType::ObjCId: + // FIXME: Make sure that the "to" context supports Objective-C! + return Importer.getToContext().ObjCBuiltinIdTy; + + case BuiltinType::ObjCClass: + return Importer.getToContext().ObjCBuiltinClassTy; + + case BuiltinType::ObjCSel: + return Importer.getToContext().ObjCBuiltinSelTy; + } + + return QualType(); +} + +QualType ASTNodeImporter::VisitComplexType(ComplexType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getComplexType(ToElementType); +} + +QualType ASTNodeImporter::VisitPointerType(PointerType *T) { + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getPointerType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitBlockPointerType(BlockPointerType *T) { + // FIXME: Check for blocks support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getBlockPointerType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitLValueReferenceType(LValueReferenceType *T) { + // FIXME: Check for C++ support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getLValueReferenceType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitRValueReferenceType(RValueReferenceType *T) { + // FIXME: Check for C++0x support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getRValueReferenceType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitMemberPointerType(MemberPointerType *T) { + // FIXME: Check for C++ support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + QualType ClassType = Importer.Import(QualType(T->getClass(), 0)); + return Importer.getToContext().getMemberPointerType(ToPointeeType, + ClassType.getTypePtr()); +} + +QualType ASTNodeImporter::VisitConstantArrayType(ConstantArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getConstantArrayType(ToElementType, + T->getSize(), + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); +} + +QualType ASTNodeImporter::VisitIncompleteArrayType(IncompleteArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getIncompleteArrayType(ToElementType, + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); +} + +QualType ASTNodeImporter::VisitVariableArrayType(VariableArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + Expr *Size = Importer.Import(T->getSizeExpr()); + if (!Size) + return QualType(); + + SourceRange Brackets = Importer.Import(T->getBracketsRange()); + return Importer.getToContext().getVariableArrayType(ToElementType, Size, + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), + Brackets); +} + +QualType ASTNodeImporter::VisitVectorType(VectorType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getVectorType(ToElementType, + T->getNumElements(), + T->isAltiVec(), + T->isPixel()); +} + +QualType ASTNodeImporter::VisitExtVectorType(ExtVectorType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getExtVectorType(ToElementType, + T->getNumElements()); +} + +QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) { + // FIXME: What happens if we're importing a function without a prototype + // into C++? Should we make it variadic? + QualType ToResultType = Importer.Import(T->getResultType()); + if (ToResultType.isNull()) + return QualType(); + + return Importer.getToContext().getFunctionNoProtoType(ToResultType, + T->getNoReturnAttr(), + T->getCallConv()); +} + +QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) { + QualType ToResultType = Importer.Import(T->getResultType()); + if (ToResultType.isNull()) + return QualType(); + + // Import argument types + llvm::SmallVector<QualType, 4> ArgTypes; + for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), + AEnd = T->arg_type_end(); + A != AEnd; ++A) { + QualType ArgType = Importer.Import(*A); + if (ArgType.isNull()) + return QualType(); + ArgTypes.push_back(ArgType); + } + + // Import exception types + llvm::SmallVector<QualType, 4> ExceptionTypes; + for (FunctionProtoType::exception_iterator E = T->exception_begin(), + EEnd = T->exception_end(); + E != EEnd; ++E) { + QualType ExceptionType = Importer.Import(*E); + if (ExceptionType.isNull()) + return QualType(); + ExceptionTypes.push_back(ExceptionType); + } + + return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(), + ArgTypes.size(), + T->isVariadic(), + T->getTypeQuals(), + T->hasExceptionSpec(), + T->hasAnyExceptionSpec(), + ExceptionTypes.size(), + ExceptionTypes.data(), + T->getNoReturnAttr(), + T->getCallConv()); +} + +QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) { + TypedefDecl *ToDecl + = dyn_cast_or_null<TypedefDecl>(Importer.Import(T->getDecl())); + if (!ToDecl) + return QualType(); + + return Importer.getToContext().getTypeDeclType(ToDecl); +} + +QualType ASTNodeImporter::VisitTypeOfExprType(TypeOfExprType *T) { + Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); + if (!ToExpr) + return QualType(); + + return Importer.getToContext().getTypeOfExprType(ToExpr); +} + +QualType ASTNodeImporter::VisitTypeOfType(TypeOfType *T) { + QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); + if (ToUnderlyingType.isNull()) + return QualType(); + + return Importer.getToContext().getTypeOfType(ToUnderlyingType); +} + +QualType ASTNodeImporter::VisitDecltypeType(DecltypeType *T) { + Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); + if (!ToExpr) + return QualType(); + + return Importer.getToContext().getDecltypeType(ToExpr); +} + +QualType ASTNodeImporter::VisitRecordType(RecordType *T) { + RecordDecl *ToDecl + = dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl())); + if (!ToDecl) + return QualType(); + + return Importer.getToContext().getTagDeclType(ToDecl); +} + +QualType ASTNodeImporter::VisitEnumType(EnumType *T) { + EnumDecl *ToDecl + = dyn_cast_or_null<EnumDecl>(Importer.Import(T->getDecl())); + if (!ToDecl) + return QualType(); + + return Importer.getToContext().getTagDeclType(ToDecl); +} + +QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) { + QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); + if (ToUnderlyingType.isNull()) + return QualType(); + + return Importer.getToContext().getElaboratedType(ToUnderlyingType, + T->getTagKind()); +} + +QualType ASTNodeImporter::VisitQualifiedNameType(QualifiedNameType *T) { + NestedNameSpecifier *ToQualifier = Importer.Import(T->getQualifier()); + if (!ToQualifier) + return QualType(); + + QualType ToNamedType = Importer.Import(T->getNamedType()); + if (ToNamedType.isNull()) + return QualType(); + + return Importer.getToContext().getQualifiedNameType(ToQualifier, ToNamedType); +} + +QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) { + ObjCInterfaceDecl *Class + = dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl())); + if (!Class) + return QualType(); + + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + for (ObjCInterfaceType::qual_iterator P = T->qual_begin(), + PEnd = T->qual_end(); + P != PEnd; ++P) { + ObjCProtocolDecl *Protocol + = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P)); + if (!Protocol) + return QualType(); + Protocols.push_back(Protocol); + } + + return Importer.getToContext().getObjCInterfaceType(Class, + Protocols.data(), + Protocols.size()); +} + +QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) { + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + for (ObjCObjectPointerType::qual_iterator P = T->qual_begin(), + PEnd = T->qual_end(); + P != PEnd; ++P) { + ObjCProtocolDecl *Protocol + = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P)); + if (!Protocol) + return QualType(); + Protocols.push_back(Protocol); + } + + return Importer.getToContext().getObjCObjectPointerType(ToPointeeType, + Protocols.data(), + Protocols.size()); +} + +//---------------------------------------------------------------------------- +// Import Declarations +//---------------------------------------------------------------------------- +bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC, + DeclContext *&LexicalDC, + DeclarationName &Name, + SourceLocation &Loc) { + // Import the context of this declaration. + DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return true; + + LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return true; + } + + // Import the name of this declaration. + Name = Importer.Import(D->getDeclName()); + if (D->getDeclName() && !Name) + return true; + + // Import the location of this declaration. + Loc = Importer.Import(D->getLocation()); + return false; +} + +bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, + RecordDecl *ToRecord) { + StructuralEquivalenceContext SEC(Importer.getFromContext(), + Importer.getToContext(), + Importer.getDiags(), + Importer.getNonEquivalentDecls()); + return SEC.IsStructurallyEquivalent(FromRecord, ToRecord); +} + +bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { + StructuralEquivalenceContext SEC(Importer.getFromContext(), + Importer.getToContext(), + Importer.getDiags(), + Importer.getNonEquivalentDecls()); + return SEC.IsStructurallyEquivalent(FromEnum, ToEnum); +} + +Decl *ASTNodeImporter::VisitDecl(Decl *D) { + Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) + << D->getDeclKindName(); + return 0; +} + +Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { + // Import the major distinguishing characteristics of this typedef. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // If this typedef is not in block scope, determine whether we've + // seen a typedef with the same name (that we can merge with) or any + // other entity by that name (which name lookup could conflict with). + if (!DC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + if (TypedefDecl *FoundTypedef = dyn_cast<TypedefDecl>(*Lookup.first)) { + if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(), + FoundTypedef->getUnderlyingType())) + return Importer.Imported(D, FoundTypedef); + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + // Import the underlying type of this typedef; + QualType T = Importer.Import(D->getUnderlyingType()); + if (T.isNull()) + return 0; + + // Create the new typedef node. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + TypedefDecl *ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), + TInfo); + ToTypedef->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToTypedef); + LexicalDC->addDecl(ToTypedef); + + return ToTypedef; +} + +Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { + // Import the major distinguishing characteristics of this enum. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Figure out what enum name we're looking for. + unsigned IDNS = Decl::IDNS_Tag; + DeclarationName SearchName = Name; + if (!SearchName && D->getTypedefForAnonDecl()) { + SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName()); + IDNS = Decl::IDNS_Ordinary; + } else if (Importer.getToContext().getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Ordinary; + + // We may already have an enum of the same name; try to find and match it. + if (!DC->isFunctionOrMethod() && SearchName) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + Decl *Found = *Lookup.first; + if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) { + if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) + Found = Tag->getDecl(); + } + + if (EnumDecl *FoundEnum = dyn_cast<EnumDecl>(Found)) { + if (IsStructuralMatch(D, FoundEnum)) + return Importer.Imported(D, FoundEnum); + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + } + + // Create the enum declaration. + EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getTagKeywordLoc()), + 0); + D2->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, D2); + LexicalDC->addDecl(D2); + + // Import the integer type. + QualType ToIntegerType = Importer.Import(D->getIntegerType()); + if (ToIntegerType.isNull()) + return 0; + D2->setIntegerType(ToIntegerType); + + // Import the definition + if (D->isDefinition()) { + QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(D)); + if (T.isNull()) + return 0; + + QualType ToPromotionType = Importer.Import(D->getPromotionType()); + if (ToPromotionType.isNull()) + return 0; + + D2->startDefinition(); + for (DeclContext::decl_iterator FromMem = D->decls_begin(), + FromMemEnd = D->decls_end(); + FromMem != FromMemEnd; + ++FromMem) + Importer.Import(*FromMem); + + D2->completeDefinition(T, ToPromotionType); + } + + return D2; +} + +Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { + // If this record has a definition in the translation unit we're coming from, + // but this particular declaration is not that definition, import the + // definition and map to that. + TagDecl *Definition = D->getDefinition(); + if (Definition && Definition != D) { + Decl *ImportedDef = Importer.Import(Definition); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + // Import the major distinguishing characteristics of this record. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Figure out what structure name we're looking for. + unsigned IDNS = Decl::IDNS_Tag; + DeclarationName SearchName = Name; + if (!SearchName && D->getTypedefForAnonDecl()) { + SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName()); + IDNS = Decl::IDNS_Ordinary; + } else if (Importer.getToContext().getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Ordinary; + + // We may already have a record of the same name; try to find and match it. + RecordDecl *AdoptDecl = 0; + if (!DC->isFunctionOrMethod() && SearchName) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + Decl *Found = *Lookup.first; + if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) { + if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) + Found = Tag->getDecl(); + } + + if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) { + if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { + if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // function. + // FIXME: For C++, we should also merge methods here. + return Importer.Imported(D, FoundDef); + } + } else { + // We have a forward declaration of this type, so adopt that forward + // declaration rather than building a new one. + AdoptDecl = FoundRecord; + continue; + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + } + + // Create the record declaration. + RecordDecl *D2 = AdoptDecl; + if (!D2) { + if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D)) { + CXXRecordDecl *D2CXX = CXXRecordDecl::Create(Importer.getToContext(), + D->getTagKind(), + DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getTagKeywordLoc())); + D2 = D2CXX; + + if (D->isDefinition()) { + // Add base classes. + llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; + for (CXXRecordDecl::base_class_iterator + Base1 = D1CXX->bases_begin(), + FromBaseEnd = D1CXX->bases_end(); + Base1 != FromBaseEnd; + ++Base1) { + QualType T = Importer.Import(Base1->getType()); + if (T.isNull()) + return 0; + + Bases.push_back( + new (Importer.getToContext()) + CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()), + Base1->isVirtual(), + Base1->isBaseOfClass(), + Base1->getAccessSpecifierAsWritten(), + T)); + } + if (!Bases.empty()) + D2CXX->setBases(Bases.data(), Bases.size()); + } + } else { + D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(), + DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getTagKeywordLoc())); + } + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(D2); + } + + Importer.Imported(D, D2); + + if (D->isDefinition()) { + D2->startDefinition(); + for (DeclContext::decl_iterator FromMem = D->decls_begin(), + FromMemEnd = D->decls_end(); + FromMem != FromMemEnd; + ++FromMem) + Importer.Import(*FromMem); + + D2->completeDefinition(); + } + + return D2; +} + +Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { + // Import the major distinguishing characteristics of this enumerator. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Determine whether there are any other declarations with the same name and + // in the same context. + if (!LexicalDC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + Expr *Init = Importer.Import(D->getInitExpr()); + if (D->getInitExpr() && !Init) + return 0; + + EnumConstantDecl *ToEnumerator + = EnumConstantDecl::Create(Importer.getToContext(), cast<EnumDecl>(DC), Loc, + Name.getAsIdentifierInfo(), T, + Init, D->getInitVal()); + ToEnumerator->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToEnumerator); + LexicalDC->addDecl(ToEnumerator); + return ToEnumerator; +} + +Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { + // Import the major distinguishing characteristics of this function. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Try to find a function in our own ("to") context with the same name, same + // type, and in the same context as the function we're importing. + if (!LexicalDC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(*Lookup.first)) { + if (isExternalLinkage(FoundFunction->getLinkage()) && + isExternalLinkage(D->getLinkage())) { + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundFunction->getType())) { + // FIXME: Actually try to merge the body and other attributes. + return Importer.Imported(D, FoundFunction); + } + + // FIXME: Check for overloading more carefully, e.g., by boosting + // Sema::IsOverload out to the AST library. + + // Function overloading is okay in C++. + if (Importer.getToContext().getLangOptions().CPlusPlus) + continue; + + // Complain about inconsistent function types. + Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent) + << Name << D->getType() << FoundFunction->getType(); + Importer.ToDiag(FoundFunction->getLocation(), + diag::note_odr_value_here) + << FoundFunction->getType(); + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Import the function parameters. + llvm::SmallVector<ParmVarDecl *, 8> Parameters; + for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); + P != PEnd; ++P) { + ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*P)); + if (!ToP) + return 0; + + Parameters.push_back(ToP); + } + + // Create the imported function. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + FunctionDecl *ToEnumerator + = FunctionDecl::Create(Importer.getToContext(), DC, Loc, + Name, T, TInfo, D->getStorageClass(), + D->isInlineSpecified(), + D->hasWrittenPrototype()); + ToEnumerator->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToEnumerator); + LexicalDC->addDecl(ToEnumerator); + + // Set the parameters. + for (unsigned I = 0, N = Parameters.size(); I != N; ++I) { + Parameters[I]->setOwningFunction(ToEnumerator); + ToEnumerator->addDecl(Parameters[I]); + } + ToEnumerator->setParams(Parameters.data(), Parameters.size()); + + // FIXME: Other bits to merge? + + return ToEnumerator; +} + +Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { + // Import the major distinguishing characteristics of a variable. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + Expr *BitWidth = Importer.Import(D->getBitWidth()); + if (!BitWidth && D->getBitWidth()) + return 0; + + FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), + T, TInfo, BitWidth, D->isMutable()); + ToField->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToField); + LexicalDC->addDecl(ToField); + return ToField; +} + +Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { + // Import the major distinguishing characteristics of a variable. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Try to find a variable in our own ("to") context with the same name and + // in the same context as the variable we're importing. + if (D->isFileVarDecl()) { + VarDecl *MergeWithVar = 0; + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + if (VarDecl *FoundVar = dyn_cast<VarDecl>(*Lookup.first)) { + // We have found a variable that we may need to merge with. Check it. + if (isExternalLinkage(FoundVar->getLinkage()) && + isExternalLinkage(D->getLinkage())) { + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundVar->getType())) { + MergeWithVar = FoundVar; + break; + } + + const ArrayType *FoundArray + = Importer.getToContext().getAsArrayType(FoundVar->getType()); + const ArrayType *TArray + = Importer.getToContext().getAsArrayType(D->getType()); + if (FoundArray && TArray) { + if (isa<IncompleteArrayType>(FoundArray) && + isa<ConstantArrayType>(TArray)) { + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + FoundVar->setType(T); + MergeWithVar = FoundVar; + break; + } else if (isa<IncompleteArrayType>(TArray) && + isa<ConstantArrayType>(FoundArray)) { + MergeWithVar = FoundVar; + break; + } + } + + Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent) + << Name << D->getType() << FoundVar->getType(); + Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here) + << FoundVar->getType(); + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (MergeWithVar) { + // An equivalent variable with external linkage has been found. Link + // the two declarations, then merge them. + Importer.Imported(D, MergeWithVar); + + if (VarDecl *DDef = D->getDefinition()) { + if (VarDecl *ExistingDef = MergeWithVar->getDefinition()) { + Importer.ToDiag(ExistingDef->getLocation(), + diag::err_odr_variable_multiple_def) + << Name; + Importer.FromDiag(DDef->getLocation(), diag::note_odr_defined_here); + } else { + Expr *Init = Importer.Import(DDef->getInit()); + MergeWithVar->setInit(Init); + } + } + + return MergeWithVar; + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Create the imported variable. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, + Name.getAsIdentifierInfo(), T, TInfo, + D->getStorageClass()); + ToVar->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToVar); + LexicalDC->addDecl(ToVar); + + // Merge the initializer. + // FIXME: Can we really import any initializer? Alternatively, we could force + // ourselves to import every declaration of a variable and then only use + // getInit() here. + ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer()))); + + // FIXME: Other bits to merge? + + return ToVar; +} + +Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { + // Parameters are created in the translation unit's context, then moved + // into the function declaration's context afterward. + DeclContext *DC = Importer.getToContext().getTranslationUnitDecl(); + + // Import the name of this declaration. + DeclarationName Name = Importer.Import(D->getDeclName()); + if (D->getDeclName() && !Name) + return 0; + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + // Import the parameter's type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Create the imported parameter. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), + T, TInfo, D->getStorageClass(), + /*FIXME: Default argument*/ 0); + return Importer.Imported(D, ToParm); +} + +Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + // Import the major distinguishing characteristics of an @interface. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + ObjCInterfaceDecl *MergeWithIface = 0; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + continue; + + if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(*Lookup.first))) + break; + } + + ObjCInterfaceDecl *ToIface = MergeWithIface; + if (!ToIface || ToIface->isForwardDecl()) { + if (!ToIface) { + ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), + DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getClassLoc()), + D->isForwardDecl(), + D->isImplicitInterfaceDecl()); + ToIface->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToIface); + } + Importer.Imported(D, ToIface); + + // Import superclass + // FIXME: If we're merging, make sure that both decls have the same + // superclass. + if (D->getSuperClass()) { + ObjCInterfaceDecl *Super + = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getSuperClass())); + if (!Super) + return 0; + + ToIface->setSuperClass(Super); + ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc())); + } + + // Import protocols + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + llvm::SmallVector<SourceLocation, 4> ProtocolLocs; + ObjCInterfaceDecl::protocol_loc_iterator + FromProtoLoc = D->protocol_loc_begin(); + for (ObjCInterfaceDecl::protocol_iterator FromProto = D->protocol_begin(), + FromProtoEnd = D->protocol_end(); + FromProto != FromProtoEnd; + ++FromProto, ++FromProtoLoc) { + ObjCProtocolDecl *ToProto + = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); + if (!ToProto) + return 0; + Protocols.push_back(ToProto); + ProtocolLocs.push_back(Importer.Import(*FromProtoLoc)); + } + + // FIXME: If we're merging, make sure that the protocol list is the same. + ToIface->setProtocolList(Protocols.data(), Protocols.size(), + ProtocolLocs.data(), Importer.getToContext()); + + // FIXME: Import categories + + // Import @end range + ToIface->setAtEndRange(Importer.Import(D->getAtEndRange())); + } else { + Importer.Imported(D, ToIface); + } + + // Import all of the members of this class. + for (DeclContext::decl_iterator FromMem = D->decls_begin(), + FromMemEnd = D->decls_end(); + FromMem != FromMemEnd; + ++FromMem) + Importer.Import(*FromMem); + + // If we have an @implementation, import it as well. + if (D->getImplementation()) { + ObjCImplementationDecl *Impl + = cast<ObjCImplementationDecl>(Importer.Import(D->getImplementation())); + if (!Impl) + return 0; + + ToIface->setImplementation(Impl); + } + + return 0; +} + +//---------------------------------------------------------------------------- +// Import Statements +//---------------------------------------------------------------------------- + +Stmt *ASTNodeImporter::VisitStmt(Stmt *S) { + Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node) + << S->getStmtClassName(); + return 0; +} + +//---------------------------------------------------------------------------- +// Import Expressions +//---------------------------------------------------------------------------- +Expr *ASTNodeImporter::VisitExpr(Expr *E) { + Importer.FromDiag(E->getLocStart(), diag::err_unsupported_ast_node) + << E->getStmtClassName(); + return 0; +} + +Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + return new (Importer.getToContext()) + IntegerLiteral(E->getValue(), T, Importer.Import(E->getLocation())); +} + +Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + Expr *SubExpr = Importer.Import(E->getSubExpr()); + if (!SubExpr) + return 0; + + return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(), + SubExpr, + E->isLvalueCast()); +} + +ASTImporter::ASTImporter(Diagnostic &Diags, + ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager) + : ToContext(ToContext), FromContext(FromContext), + ToFileManager(ToFileManager), FromFileManager(FromFileManager), + Diags(Diags) { + ImportedDecls[FromContext.getTranslationUnitDecl()] + = ToContext.getTranslationUnitDecl(); +} + +ASTImporter::~ASTImporter() { } + +QualType ASTImporter::Import(QualType FromT) { + if (FromT.isNull()) + return QualType(); + + // Check whether we've already imported this type. + llvm::DenseMap<Type *, Type *>::iterator Pos + = ImportedTypes.find(FromT.getTypePtr()); + if (Pos != ImportedTypes.end()) + return ToContext.getQualifiedType(Pos->second, FromT.getQualifiers()); + + // Import the type + ASTNodeImporter Importer(*this); + QualType ToT = Importer.Visit(FromT.getTypePtr()); + if (ToT.isNull()) + return ToT; + + // Record the imported type. + ImportedTypes[FromT.getTypePtr()] = ToT.getTypePtr(); + + return ToContext.getQualifiedType(ToT, FromT.getQualifiers()); +} + +TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { + if (!FromTSI) + return FromTSI; + + // FIXME: For now we just create a "trivial" type source info based + // on the type and a seingle location. Implement a real version of + // this. + QualType T = Import(FromTSI->getType()); + if (T.isNull()) + return 0; + + return ToContext.getTrivialTypeSourceInfo(T, + FromTSI->getTypeLoc().getFullSourceRange().getBegin()); +} + +Decl *ASTImporter::Import(Decl *FromD) { + if (!FromD) + return 0; + + // Check whether we've already imported this declaration. + llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD); + if (Pos != ImportedDecls.end()) + return Pos->second; + + // Import the type + ASTNodeImporter Importer(*this); + Decl *ToD = Importer.Visit(FromD); + if (!ToD) + return 0; + + // Record the imported declaration. + ImportedDecls[FromD] = ToD; + + if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) { + // Keep track of anonymous tags that have an associated typedef. + if (FromTag->getTypedefForAnonDecl()) + AnonTagsWithPendingTypedefs.push_back(FromTag); + } else if (TypedefDecl *FromTypedef = dyn_cast<TypedefDecl>(FromD)) { + // When we've finished transforming a typedef, see whether it was the + // typedef for an anonymous tag. + for (llvm::SmallVector<TagDecl *, 4>::iterator + FromTag = AnonTagsWithPendingTypedefs.begin(), + FromTagEnd = AnonTagsWithPendingTypedefs.end(); + FromTag != FromTagEnd; ++FromTag) { + if ((*FromTag)->getTypedefForAnonDecl() == FromTypedef) { + if (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) { + // We found the typedef for an anonymous tag; link them. + ToTag->setTypedefForAnonDecl(cast<TypedefDecl>(ToD)); + AnonTagsWithPendingTypedefs.erase(FromTag); + break; + } + } + } + } + + return ToD; +} + +DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) { + if (!FromDC) + return FromDC; + + return cast_or_null<DeclContext>(Import(cast<Decl>(FromDC))); +} + +Expr *ASTImporter::Import(Expr *FromE) { + if (!FromE) + return 0; + + return cast_or_null<Expr>(Import(cast<Stmt>(FromE))); +} + +Stmt *ASTImporter::Import(Stmt *FromS) { + if (!FromS) + return 0; + + // Check whether we've already imported this declaration. + llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS); + if (Pos != ImportedStmts.end()) + return Pos->second; + + // Import the type + ASTNodeImporter Importer(*this); + Stmt *ToS = Importer.Visit(FromS); + if (!ToS) + return 0; + + // Record the imported declaration. + ImportedStmts[FromS] = ToS; + return ToS; +} + +NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { + if (!FromNNS) + return 0; + + // FIXME: Implement! + return 0; +} + +SourceLocation ASTImporter::Import(SourceLocation FromLoc) { + if (FromLoc.isInvalid()) + return SourceLocation(); + + SourceManager &FromSM = FromContext.getSourceManager(); + + // For now, map everything down to its spelling location, so that we + // don't have to import macro instantiations. + // FIXME: Import macro instantiations! + FromLoc = FromSM.getSpellingLoc(FromLoc); + std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc); + SourceManager &ToSM = ToContext.getSourceManager(); + return ToSM.getLocForStartOfFile(Import(Decomposed.first)) + .getFileLocWithOffset(Decomposed.second); +} + +SourceRange ASTImporter::Import(SourceRange FromRange) { + return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd())); +} + +FileID ASTImporter::Import(FileID FromID) { + llvm::DenseMap<unsigned, FileID>::iterator Pos + = ImportedFileIDs.find(FromID.getHashValue()); + if (Pos != ImportedFileIDs.end()) + return Pos->second; + + SourceManager &FromSM = FromContext.getSourceManager(); + SourceManager &ToSM = ToContext.getSourceManager(); + const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID); + assert(FromSLoc.isFile() && "Cannot handle macro instantiations yet"); + + // Include location of this file. + SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); + + // Map the FileID for to the "to" source manager. + FileID ToID; + const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); + if (Cache->Entry) { + // FIXME: We probably want to use getVirtualFile(), so we don't hit the + // disk again + // FIXME: We definitely want to re-use the existing MemoryBuffer, rather + // than mmap the files several times. + const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName()); + ToID = ToSM.createFileID(Entry, ToIncludeLoc, + FromSLoc.getFile().getFileCharacteristic()); + } else { + // FIXME: We want to re-use the existing MemoryBuffer! + const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(); + llvm::MemoryBuffer *ToBuf + = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBufferStart(), + FromBuf->getBufferEnd(), + FromBuf->getBufferIdentifier()); + ToID = ToSM.createFileIDForMemBuffer(ToBuf); + } + + + ImportedFileIDs[FromID.getHashValue()] = ToID; + return ToID; +} + +DeclarationName ASTImporter::Import(DeclarationName FromName) { + if (!FromName) + return DeclarationName(); + + switch (FromName.getNameKind()) { + case DeclarationName::Identifier: + return Import(FromName.getAsIdentifierInfo()); + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return Import(FromName.getObjCSelector()); + + case DeclarationName::CXXConstructorName: { + QualType T = Import(FromName.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return ToContext.DeclarationNames.getCXXConstructorName( + ToContext.getCanonicalType(T)); + } + + case DeclarationName::CXXDestructorName: { + QualType T = Import(FromName.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return ToContext.DeclarationNames.getCXXDestructorName( + ToContext.getCanonicalType(T)); + } + + case DeclarationName::CXXConversionFunctionName: { + QualType T = Import(FromName.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return ToContext.DeclarationNames.getCXXConversionFunctionName( + ToContext.getCanonicalType(T)); + } + + case DeclarationName::CXXOperatorName: + return ToContext.DeclarationNames.getCXXOperatorName( + FromName.getCXXOverloadedOperator()); + + case DeclarationName::CXXLiteralOperatorName: + return ToContext.DeclarationNames.getCXXLiteralOperatorName( + Import(FromName.getCXXLiteralIdentifier())); + + case DeclarationName::CXXUsingDirective: + // FIXME: STATICS! + return DeclarationName::getUsingDirectiveName(); + } + + // Silence bogus GCC warning + return DeclarationName(); +} + +IdentifierInfo *ASTImporter::Import(IdentifierInfo *FromId) { + if (!FromId) + return 0; + + return &ToContext.Idents.get(FromId->getName()); +} + +DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name, + DeclContext *DC, + unsigned IDNS, + NamedDecl **Decls, + unsigned NumDecls) { + return Name; +} + +DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(FullSourceLoc(Loc, ToContext.getSourceManager()), + DiagID); +} + +DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(FullSourceLoc(Loc, FromContext.getSourceManager()), + DiagID); +} + +Decl *ASTImporter::Imported(Decl *From, Decl *To) { + ImportedDecls[From] = To; + return To; +} + +bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To) { + llvm::DenseMap<Type *, Type *>::iterator Pos + = ImportedTypes.find(From.getTypePtr()); + if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To)) + return true; + + StructuralEquivalenceContext SEC(FromContext, ToContext, Diags, + NonEquivalentDecls); + return SEC.IsStructurallyEquivalent(From, To); +} diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index 02c70b651119..d81979734b3a 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -11,11 +11,61 @@ // //===----------------------------------------------------------------------===// - #include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" using namespace clang; +void Attr::Destroy(ASTContext &C) { + if (Next) { + Next->Destroy(C); + Next = 0; + } + this->~Attr(); + C.Deallocate((void*)this); +} + +AttrWithString::AttrWithString(Attr::Kind AK, ASTContext &C, llvm::StringRef s) + : Attr(AK) { + assert(!s.empty()); + StrLen = s.size(); + Str = new (C) char[StrLen]; + memcpy(const_cast<char*>(Str), s.data(), StrLen); +} + +void AttrWithString::Destroy(ASTContext &C) { + C.Deallocate(const_cast<char*>(Str)); + Attr::Destroy(C); +} + +void AttrWithString::ReplaceString(ASTContext &C, llvm::StringRef newS) { + if (newS.size() > StrLen) { + C.Deallocate(const_cast<char*>(Str)); + Str = new (C) char[newS.size()]; + } + StrLen = newS.size(); + memcpy(const_cast<char*>(Str), newS.data(), StrLen); +} + +void FormatAttr::setType(ASTContext &C, llvm::StringRef type) { + ReplaceString(C, type); +} + +NonNullAttr::NonNullAttr(ASTContext &C, unsigned* arg_nums, unsigned size) + : Attr(NonNull), ArgNums(0), Size(0) { + if (size == 0) + return; + assert(arg_nums); + ArgNums = new (C) unsigned[size]; + Size = size; + memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size); +} + +void NonNullAttr::Destroy(ASTContext &C) { + if (ArgNums) + C.Deallocate(ArgNums); + Attr::Destroy(C); +} + #define DEF_SIMPLE_ATTR_CLONE(ATTR) \ Attr *ATTR##Attr::clone(ASTContext &C) const { \ return ::new (C) ATTR##Attr; \ @@ -55,6 +105,7 @@ DEF_SIMPLE_ATTR_CLONE(Hiding) DEF_SIMPLE_ATTR_CLONE(Override) DEF_SIMPLE_ATTR_CLONE(DLLImport) DEF_SIMPLE_ATTR_CLONE(DLLExport) +DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer) Attr* PragmaPackAttr::clone(ASTContext &C) const { return ::new (C) PragmaPackAttr(Alignment); @@ -65,15 +116,15 @@ Attr* AlignedAttr::clone(ASTContext &C) const { } Attr* AnnotateAttr::clone(ASTContext &C) const { - return ::new (C) AnnotateAttr(Annotation); + return ::new (C) AnnotateAttr(C, getAnnotation()); } Attr *AsmLabelAttr::clone(ASTContext &C) const { - return ::new (C) AsmLabelAttr(Label); + return ::new (C) AsmLabelAttr(C, getLabel()); } Attr *AliasAttr::clone(ASTContext &C) const { - return ::new (C) AliasAttr(Aliasee); + return ::new (C) AliasAttr(C, getAliasee()); } Attr *ConstructorAttr::clone(ASTContext &C) const { @@ -93,15 +144,15 @@ Attr *GNUInlineAttr::clone(ASTContext &C) const { } Attr *SectionAttr::clone(ASTContext &C) const { - return ::new (C) SectionAttr(Name); + return ::new (C) SectionAttr(C, getName()); } Attr *NonNullAttr::clone(ASTContext &C) const { - return ::new (C) NonNullAttr(ArgNums, Size); + return ::new (C) NonNullAttr(C, ArgNums, Size); } Attr *FormatAttr::clone(ASTContext &C) const { - return ::new (C) FormatAttr(Type, formatIdx, firstArg); + return ::new (C) FormatAttr(C, getType(), formatIdx, firstArg); } Attr *FormatArgAttr::clone(ASTContext &C) const { diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index dea96e7866ec..e5bd9b7722c5 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -4,6 +4,8 @@ add_clang_library(clangAST APValue.cpp ASTConsumer.cpp ASTContext.cpp + ASTImporter.cpp + ASTDiagnostic.cpp AttrImpl.cpp CXXInheritance.cpp Decl.cpp diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 720832869266..99f908caeab6 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -102,7 +102,6 @@ bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const { bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, void *OpaqueData, bool AllowShortCircuit) const { - ASTContext &Context = getASTContext(); llvm::SmallVector<const CXXRecordDecl*, 8> Queue; const CXXRecordDecl *Record = this; @@ -118,7 +117,7 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, } CXXRecordDecl *Base = - cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition(Context)); + cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition()); if (!Base) { if (AllowShortCircuit) return false; AllMatches = false; @@ -215,10 +214,13 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, Paths.ScratchPath.Access = MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier()); } - + + // Track whether there's a path involving this specific base. + bool FoundPathThroughBase = false; + if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) { // We've found a path that terminates at this base. - FoundPath = true; + FoundPath = FoundPathThroughBase = true; if (Paths.isRecordingPaths()) { // We have a path. Make a copy of it before moving on. Paths.Paths.push_back(Paths.ScratchPath); @@ -240,7 +242,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, // There is a path to a base class that meets the criteria. If we're // not collecting paths or finding ambiguities, we're done. - FoundPath = true; + FoundPath = FoundPathThroughBase = true; if (!Paths.isFindingAmbiguities()) return FoundPath; } @@ -253,7 +255,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, } // If we set a virtual earlier, and this isn't a path, forget it again. - if (SetVirtual && !FoundPath) { + if (SetVirtual && !FoundPathThroughBase) { Paths.DetectedVirtual = 0; } } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 794b14a1f4a1..5acb82f31a29 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -29,224 +29,81 @@ using namespace clang; -void Attr::Destroy(ASTContext &C) { - if (Next) { - Next->Destroy(C); - Next = 0; - } - this->~Attr(); - C.Deallocate((void*)this); -} - /// \brief Return the TypeLoc wrapper for the type source info. TypeLoc TypeSourceInfo::getTypeLoc() const { return TypeLoc(Ty, (void*)(this + 1)); } //===----------------------------------------------------------------------===// -// Decl Allocation/Deallocation Method Implementations +// NamedDecl Implementation //===----------------------------------------------------------------------===// +/// \brief Get the most restrictive linkage for the types in the given +/// template parameter list. +static Linkage +getLinkageForTemplateParameterList(const TemplateParameterList *Params) { + Linkage L = ExternalLinkage; + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) + if (!NTTP->getType()->isDependentType()) { + L = minLinkage(L, NTTP->getType()->getLinkage()); + continue; + } -TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { - return new (C) TranslationUnitDecl(C); -} - -NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id) { - return new (C) NamespaceDecl(DC, L, Id); -} - -void NamespaceDecl::Destroy(ASTContext& C) { - // NamespaceDecl uses "NextDeclarator" to chain namespace declarations - // together. They are all top-level Decls. - - this->~NamespaceDecl(); - C.Deallocate((void *)this); -} - - -ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, QualType T) { - return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T); -} - -const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { - switch (SC) { - case VarDecl::None: break; - case VarDecl::Auto: return "auto"; break; - case VarDecl::Extern: return "extern"; break; - case VarDecl::PrivateExtern: return "__private_extern__"; break; - case VarDecl::Register: return "register"; break; - case VarDecl::Static: return "static"; break; + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(*P)) { + L = minLinkage(L, + getLinkageForTemplateParameterList(TTP->getTemplateParameters())); + } } - assert(0 && "Invalid storage class"); - return 0; -} - -ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); -} - -Expr *ParmVarDecl::getDefaultArg() { - assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); - assert(!hasUninstantiatedDefaultArg() && - "Default argument is not yet instantiated!"); - - Expr *Arg = getInit(); - if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg)) - return E->getSubExpr(); - - return Arg; -} - -unsigned ParmVarDecl::getNumDefaultArgTemporaries() const { - if (const CXXExprWithTemporaries *E = - dyn_cast<CXXExprWithTemporaries>(getInit())) - return E->getNumTemporaries(); - - return 0; + return L; } -CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) { - assert(getNumDefaultArgTemporaries() && - "Default arguments does not have any temporaries!"); - - CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit()); - return E->getTemporary(i); -} +/// \brief Get the most restrictive linkage for the types and +/// declarations in the given template argument list. +static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args, + unsigned NumArgs) { + Linkage L = ExternalLinkage; -SourceRange ParmVarDecl::getDefaultArgRange() const { - if (const Expr *E = getInit()) - return E->getSourceRange(); - - if (hasUninstantiatedDefaultArg()) - return getUninstantiatedDefaultArg()->getSourceRange(); - - return SourceRange(); -} - -void VarDecl::setInit(ASTContext &C, Expr *I) { - if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { - Eval->~EvaluatedStmt(); - C.Deallocate(Eval); - } - - Init = I; -} + for (unsigned I = 0; I != NumArgs; ++I) { + switch (Args[I].getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Expression: + break; + + case TemplateArgument::Type: + L = minLinkage(L, Args[I].getAsType()->getLinkage()); + break; -bool VarDecl::isExternC() const { - ASTContext &Context = getASTContext(); - if (!Context.getLangOptions().CPlusPlus) - return (getDeclContext()->isTranslationUnit() && - getStorageClass() != Static) || - (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); + case TemplateArgument::Declaration: + if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl())) + L = minLinkage(L, ND->getLinkage()); + if (ValueDecl *VD = dyn_cast<ValueDecl>(Args[I].getAsDecl())) + L = minLinkage(L, VD->getType()->getLinkage()); + break; - for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); - DC = DC->getParent()) { - if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { - if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) - return getStorageClass() != Static; + case TemplateArgument::Template: + if (TemplateDecl *Template + = Args[I].getAsTemplate().getAsTemplateDecl()) + L = minLinkage(L, Template->getLinkage()); + break; + case TemplateArgument::Pack: + L = minLinkage(L, + getLinkageForTemplateArgumentList(Args[I].pack_begin(), + Args[I].pack_size())); break; } - - if (DC->isFunctionOrMethod()) - return false; } - return false; + return L; } -FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - DeclarationName N, QualType T, - TypeSourceInfo *TInfo, - StorageClass S, bool isInline, - bool hasWrittenPrototype) { - FunctionDecl *New - = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline); - New->HasWrittenPrototype = hasWrittenPrototype; - return New; -} - -BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { - return new (C) BlockDecl(DC, L); -} - -FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, - TypeSourceInfo *TInfo, Expr *BW, bool Mutable) { - return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable); -} - -bool FieldDecl::isAnonymousStructOrUnion() const { - if (!isImplicit() || getDeclName()) - return false; - - if (const RecordType *Record = getType()->getAs<RecordType>()) - return Record->getDecl()->isAnonymousStructOrUnion(); - - return false; -} - -EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, - SourceLocation L, - IdentifierInfo *Id, QualType T, - Expr *E, const llvm::APSInt &V) { - return new (C) EnumConstantDecl(CD, L, Id, T, E, V); -} - -void EnumConstantDecl::Destroy(ASTContext& C) { - if (Init) Init->Destroy(C); - Decl::Destroy(C); -} - -TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - TypeSourceInfo *TInfo) { - return new (C) TypedefDecl(DC, L, Id, TInfo); -} - -// Anchor TypedefDecl's vtable here. -TypedefDecl::~TypedefDecl() {} - -EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, SourceLocation TKL, - EnumDecl *PrevDecl) { - EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL); - C.getTypeDeclType(Enum, PrevDecl); - return Enum; -} - -void EnumDecl::Destroy(ASTContext& C) { - Decl::Destroy(C); -} - -void EnumDecl::completeDefinition(ASTContext &C, - QualType NewType, - QualType NewPromotionType) { - assert(!isDefinition() && "Cannot redefine enums!"); - IntegerType = NewType; - PromotionType = NewPromotionType; - TagDecl::completeDefinition(); -} - -FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - StringLiteral *Str) { - return new (C) FileScopeAsmDecl(DC, L, Str); -} - -//===----------------------------------------------------------------------===// -// NamedDecl Implementation -//===----------------------------------------------------------------------===// - -static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { +static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { assert(D->getDeclContext()->getLookupContext()->isFileContext() && "Not a name having namespace scope"); ASTContext &Context = D->getASTContext(); @@ -260,7 +117,7 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { // Explicitly declared static. if (Var->getStorageClass() == VarDecl::Static) - return NamedDecl::InternalLinkage; + return InternalLinkage; // - an object or reference that is explicitly declared const // and neither explicitly declared extern nor previously @@ -274,13 +131,16 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { for (const VarDecl *PrevVar = Var->getPreviousDeclaration(); PrevVar && !FoundExtern; PrevVar = PrevVar->getPreviousDeclaration()) - if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage) + if (isExternalLinkage(PrevVar->getLinkage())) FoundExtern = true; if (!FoundExtern) - return NamedDecl::InternalLinkage; + return InternalLinkage; } } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { + // C++ [temp]p4: + // A non-member function template can have internal linkage; any + // other template name shall have external linkage. const FunctionDecl *Function = 0; if (const FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) @@ -290,11 +150,11 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // Explicitly declared static. if (Function->getStorageClass() == FunctionDecl::Static) - return NamedDecl::InternalLinkage; + return InternalLinkage; } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) { // - a data member of an anonymous union. if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()) - return NamedDecl::InternalLinkage; + return InternalLinkage; } // C++ [basic.link]p4: @@ -317,7 +177,7 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // is visible, or if the prior declaration specifies no // linkage, then the identifier has external linkage. if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) { - if (NamedDecl::Linkage L = PrevVar->getLinkage()) + if (Linkage L = PrevVar->getLinkage()) return L; } } @@ -326,7 +186,10 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // If the declaration of an identifier for an object has file // scope and no storage-class specifier, its linkage is // external. - return NamedDecl::ExternalLinkage; + if (Var->isInAnonymousNamespace()) + return UniqueExternalLinkage; + + return ExternalLinkage; } // - a function, unless it has internal linkage; or @@ -350,12 +213,26 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // is visible, or if the prior declaration specifies no // linkage, then the identifier has external linkage. if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) { - if (NamedDecl::Linkage L = PrevFunc->getLinkage()) + if (Linkage L = PrevFunc->getLinkage()) return L; } } - return NamedDecl::ExternalLinkage; + if (Function->isInAnonymousNamespace()) + return UniqueExternalLinkage; + + if (FunctionTemplateSpecializationInfo *SpecInfo + = Function->getTemplateSpecializationInfo()) { + Linkage L = SpecInfo->getTemplate()->getLinkage(); + const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments; + L = minLinkage(L, + getLinkageForTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size())); + return L; + } + + return ExternalLinkage; } // - a named class (Clause 9), or an unnamed class defined in a @@ -365,29 +242,50 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // defined in a typedef declaration in which the enumeration // has the typedef name for linkage purposes (7.1.3); or if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) - if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) - return NamedDecl::ExternalLinkage; + if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) { + if (Tag->isInAnonymousNamespace()) + return UniqueExternalLinkage; + + // If this is a class template specialization, consider the + // linkage of the template and template arguments. + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + Linkage L = getLinkageForTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size()); + return minLinkage(L, Spec->getSpecializedTemplate()->getLinkage()); + } + + return ExternalLinkage; + } // - an enumerator belonging to an enumeration with external linkage; - if (isa<EnumConstantDecl>(D)) - if (cast<NamedDecl>(D->getDeclContext())->getLinkage() - == NamedDecl::ExternalLinkage) - return NamedDecl::ExternalLinkage; + if (isa<EnumConstantDecl>(D)) { + Linkage L = cast<NamedDecl>(D->getDeclContext())->getLinkage(); + if (isExternalLinkage(L)) + return L; + } // - a template, unless it is a function template that has // internal linkage (Clause 14); - if (isa<TemplateDecl>(D)) - return NamedDecl::ExternalLinkage; + if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { + if (D->isInAnonymousNamespace()) + return UniqueExternalLinkage; + + return getLinkageForTemplateParameterList( + Template->getTemplateParameters()); + } // - a namespace (7.3), unless it is declared within an unnamed // namespace. if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) - return NamedDecl::ExternalLinkage; + return ExternalLinkage; - return NamedDecl::NoLinkage; + return NoLinkage; } -NamedDecl::Linkage NamedDecl::getLinkage() const { +Linkage NamedDecl::getLinkage() const { // Handle linkage for namespace-scope names. if (getDeclContext()->getLookupContext()->isFileContext()) if (Linkage L = getLinkageForNamespaceScopeDecl(this)) @@ -403,9 +301,11 @@ NamedDecl::Linkage NamedDecl::getLinkage() const { if (getDeclContext()->isRecord() && (isa<CXXMethodDecl>(this) || isa<VarDecl>(this) || (isa<TagDecl>(this) && - (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) && - cast<RecordDecl>(getDeclContext())->getLinkage() == ExternalLinkage) - return ExternalLinkage; + (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl())))) { + Linkage L = cast<RecordDecl>(getDeclContext())->getLinkage(); + if (isExternalLinkage(L)) + return L; + } // C++ [basic.link]p6: // The name of a function declared in block scope and the name of @@ -424,6 +324,9 @@ NamedDecl::Linkage NamedDecl::getLinkage() const { if (Linkage L = Function->getPreviousDeclaration()->getLinkage()) return L; + if (Function->isInAnonymousNamespace()) + return UniqueExternalLinkage; + return ExternalLinkage; } @@ -434,6 +337,9 @@ NamedDecl::Linkage NamedDecl::getLinkage() const { if (Linkage L = Var->getPreviousDeclaration()->getLinkage()) return L; + if (Var->isInAnonymousNamespace()) + return UniqueExternalLinkage; + return ExternalLinkage; } } @@ -441,7 +347,7 @@ NamedDecl::Linkage NamedDecl::getLinkage() const { // C++ [basic.link]p6: // Names not covered by these rules have no linkage. return NoLinkage; -} + } std::string NamedDecl::getQualifiedNameAsString() const { return getQualifiedNameAsString(getASTContext().getLangOptions()); @@ -606,6 +512,20 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { // VarDecl Implementation //===----------------------------------------------------------------------===// +const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { + switch (SC) { + case VarDecl::None: break; + case VarDecl::Auto: return "auto"; break; + case VarDecl::Extern: return "extern"; break; + case VarDecl::PrivateExtern: return "__private_extern__"; break; + case VarDecl::Register: return "register"; break; + case VarDecl::Static: return "static"; break; + } + + assert(0 && "Invalid storage class"); + return 0; +} + VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S) { @@ -638,6 +558,127 @@ SourceRange VarDecl::getSourceRange() const { return SourceRange(Start, getLocation()); } +bool VarDecl::isExternC() const { + ASTContext &Context = getASTContext(); + if (!Context.getLangOptions().CPlusPlus) + return (getDeclContext()->isTranslationUnit() && + getStorageClass() != Static) || + (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); + + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { + if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) + return getStorageClass() != Static; + + break; + } + + if (DC->isFunctionOrMethod()) + return false; + } + + return false; +} + +VarDecl *VarDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + +VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const { + // C++ [basic.def]p2: + // A declaration is a definition unless [...] it contains the 'extern' + // specifier or a linkage-specification and neither an initializer [...], + // it declares a static data member in a class declaration [...]. + // C++ [temp.expl.spec]p15: + // An explicit specialization of a static data member of a template is a + // definition if the declaration includes an initializer; otherwise, it is + // a declaration. + if (isStaticDataMember()) { + if (isOutOfLine() && (hasInit() || + getTemplateSpecializationKind() != TSK_ExplicitSpecialization)) + return Definition; + else + return DeclarationOnly; + } + // C99 6.7p5: + // A definition of an identifier is a declaration for that identifier that + // [...] causes storage to be reserved for that object. + // Note: that applies for all non-file-scope objects. + // C99 6.9.2p1: + // If the declaration of an identifier for an object has file scope and an + // initializer, the declaration is an external definition for the identifier + if (hasInit()) + return Definition; + // AST for 'extern "C" int foo;' is annotated with 'extern'. + if (hasExternalStorage()) + return DeclarationOnly; + + // C99 6.9.2p2: + // A declaration of an object that has file scope without an initializer, + // and without a storage class specifier or the scs 'static', constitutes + // a tentative definition. + // No such thing in C++. + if (!getASTContext().getLangOptions().CPlusPlus && isFileVarDecl()) + return TentativeDefinition; + + // What's left is (in C, block-scope) declarations without initializers or + // external storage. These are definitions. + return Definition; +} + +VarDecl *VarDecl::getActingDefinition() { + DefinitionKind Kind = isThisDeclarationADefinition(); + if (Kind != TentativeDefinition) + return 0; + + VarDecl *LastTentative = false; + VarDecl *First = getFirstDeclaration(); + for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); + I != E; ++I) { + Kind = (*I)->isThisDeclarationADefinition(); + if (Kind == Definition) + return 0; + else if (Kind == TentativeDefinition) + LastTentative = *I; + } + return LastTentative; +} + +bool VarDecl::isTentativeDefinitionNow() const { + DefinitionKind Kind = isThisDeclarationADefinition(); + if (Kind != TentativeDefinition) + return false; + + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if ((*I)->isThisDeclarationADefinition() == Definition) + return false; + } + return true; +} + +VarDecl *VarDecl::getDefinition() { + VarDecl *First = getFirstDeclaration(); + for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); + I != E; ++I) { + if ((*I)->isThisDeclarationADefinition() == Definition) + return *I; + } + return 0; +} + +const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const { + redecl_iterator I = redecls_begin(), E = redecls_end(); + while (I != E && !I->getInit()) + ++I; + + if (I != E) { + D = *I; + return I->getInit(); + } + return 0; +} + bool VarDecl::isOutOfLine() const { if (!isStaticDataMember()) return false; @@ -667,6 +708,15 @@ VarDecl *VarDecl::getOutOfLineDefinition() { return 0; } +void VarDecl::setInit(Expr *I) { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { + Eval->~EvaluatedStmt(); + getASTContext().Deallocate(Eval); + } + + Init = I; +} + VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast<VarDecl>(MSI->getInstantiatedFrom()); @@ -675,8 +725,7 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { } TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { - if (MemberSpecializationInfo *MSI - = getASTContext().getInstantiatedFromStaticDataMember(this)) + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return MSI->getTemplateSpecializationKind(); return TSK_Undeclared; @@ -697,29 +746,53 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, MSI->setPointOfInstantiation(PointOfInstantiation); } -bool VarDecl::isTentativeDefinition(ASTContext &Context) const { - if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus) - return false; +//===----------------------------------------------------------------------===// +// ParmVarDecl Implementation +//===----------------------------------------------------------------------===// - const VarDecl *Def = 0; - return (!getDefinition(Def) && - (getStorageClass() == None || getStorageClass() == Static)); +ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); } -const Expr *VarDecl::getDefinition(const VarDecl *&Def) const { - redecl_iterator I = redecls_begin(), E = redecls_end(); - while (I != E && !I->getInit()) - ++I; +Expr *ParmVarDecl::getDefaultArg() { + assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); + assert(!hasUninstantiatedDefaultArg() && + "Default argument is not yet instantiated!"); + + Expr *Arg = getInit(); + if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg)) + return E->getSubExpr(); + + return Arg; +} + +unsigned ParmVarDecl::getNumDefaultArgTemporaries() const { + if (const CXXExprWithTemporaries *E = + dyn_cast<CXXExprWithTemporaries>(getInit())) + return E->getNumTemporaries(); - if (I != E) { - Def = *I; - return I->getInit(); - } return 0; } -VarDecl *VarDecl::getCanonicalDecl() { - return getFirstDeclaration(); +CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) { + assert(getNumDefaultArgTemporaries() && + "Default arguments does not have any temporaries!"); + + CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit()); + return E->getTemporary(i); +} + +SourceRange ParmVarDecl::getDefaultArgRange() const { + if (const Expr *E = getInit()) + return E->getSourceRange(); + + if (hasUninstantiatedDefaultArg()) + return getUninstantiatedDefaultArg()->getSourceRange(); + + return SourceRange(); } //===----------------------------------------------------------------------===// @@ -826,6 +899,26 @@ bool FunctionDecl::isGlobal() const { return true; } +void +FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { + redeclarable_base::setPreviousDeclaration(PrevDecl); + + if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { + FunctionTemplateDecl *PrevFunTmpl + = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0; + assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); + FunTmpl->setPreviousDeclaration(PrevFunTmpl); + } +} + +const FunctionDecl *FunctionDecl::getCanonicalDecl() const { + return getFirstDeclaration(); +} + +FunctionDecl *FunctionDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. /// @@ -882,14 +975,13 @@ unsigned FunctionDecl::getNumParams() const { } -void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, - unsigned NumParams) { +void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { assert(ParamInfo == 0 && "Already has param info!"); assert(NumParams == getNumParams() && "Parameter count mismatch!"); // Zero params -> null pointer. if (NumParams) { - void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); + void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams); ParamInfo = new (Mem) ParmVarDecl*[NumParams]; memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); @@ -1014,26 +1106,6 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { return false; } -void -FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { - redeclarable_base::setPreviousDeclaration(PrevDecl); - - if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { - FunctionTemplateDecl *PrevFunTmpl - = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0; - assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); - FunTmpl->setPreviousDeclaration(PrevFunTmpl); - } -} - -const FunctionDecl *FunctionDecl::getCanonicalDecl() const { - return getFirstDeclaration(); -} - -FunctionDecl *FunctionDecl::getCanonicalDecl() { - return getFirstDeclaration(); -} - /// getOverloadedOperator - Which C++ overloaded operator this /// function represents, if any. OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { @@ -1146,8 +1218,7 @@ FunctionDecl::getTemplateSpecializationArgs() const { } void -FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, - FunctionTemplateDecl *Template, +FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, void *InsertPos, TemplateSpecializationKind TSK) { @@ -1156,7 +1227,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); if (!Info) - Info = new (Context) FunctionTemplateSpecializationInfo; + Info = new (getASTContext()) FunctionTemplateSpecializationInfo; Info->Function = this; Info->Template.setPointer(Template); @@ -1254,6 +1325,26 @@ bool FunctionDecl::isOutOfLine() const { } //===----------------------------------------------------------------------===// +// FieldDecl Implementation +//===----------------------------------------------------------------------===// + +FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, Expr *BW, bool Mutable) { + return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable); +} + +bool FieldDecl::isAnonymousStructOrUnion() const { + if (!isImplicit() || getDeclName()) + return false; + + if (const RecordType *Record = getType()->getAs<RecordType>()) + return Record->getDecl()->isAnonymousStructOrUnion(); + + return false; +} + +//===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// @@ -1271,9 +1362,23 @@ void TagDecl::startDefinition() { TagT->decl.setPointer(this); TagT->decl.setInt(1); } + + if (isa<CXXRecordDecl>(this)) { + 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); + } } void TagDecl::completeDefinition() { + assert((!isa<CXXRecordDecl>(this) || + cast<CXXRecordDecl>(this)->hasDefinition()) && + "definition completed but not started"); + IsDefinition = true; if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) { assert(TagT->decl.getPointer() == this && @@ -1282,7 +1387,7 @@ void TagDecl::completeDefinition() { } } -TagDecl* TagDecl::getDefinition(ASTContext& C) const { +TagDecl* TagDecl::getDefinition() const { if (isDefinition()) return const_cast<TagDecl *>(this); @@ -1305,6 +1410,30 @@ TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) { } //===----------------------------------------------------------------------===// +// EnumDecl Implementation +//===----------------------------------------------------------------------===// + +EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, SourceLocation TKL, + EnumDecl *PrevDecl) { + EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL); + C.getTypeDeclType(Enum, PrevDecl); + return Enum; +} + +void EnumDecl::Destroy(ASTContext& C) { + Decl::Destroy(C); +} + +void EnumDecl::completeDefinition(QualType NewType, + QualType NewPromotionType) { + assert(!isDefinition() && "Cannot redefine enums!"); + IntegerType = NewType; + PromotionType = NewPromotionType; + TagDecl::completeDefinition(); +} + +//===----------------------------------------------------------------------===// // RecordDecl Implementation //===----------------------------------------------------------------------===// @@ -1341,7 +1470,7 @@ bool RecordDecl::isInjectedClassName() const { /// completeDefinition - Notes that the definition of this type is now /// complete. -void RecordDecl::completeDefinition(ASTContext& C) { +void RecordDecl::completeDefinition() { assert(!isDefinition() && "Cannot redefine record!"); TagDecl::completeDefinition(); } @@ -1364,14 +1493,14 @@ void BlockDecl::Destroy(ASTContext& C) { Decl::Destroy(C); } -void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, +void BlockDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NParms) { assert(ParamInfo == 0 && "Already has param info!"); // Zero params -> null pointer. if (NParms) { NumParams = NParms; - void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); + void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams); ParamInfo = new (Mem) ParmVarDecl*[NumParams]; memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); } @@ -1380,3 +1509,74 @@ void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned BlockDecl::getNumParams() const { return NumParams; } + + +//===----------------------------------------------------------------------===// +// Other Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { + return new (C) TranslationUnitDecl(C); +} + +NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id) { + return new (C) NamespaceDecl(DC, L, Id); +} + +void NamespaceDecl::Destroy(ASTContext& C) { + // NamespaceDecl uses "NextDeclarator" to chain namespace declarations + // together. They are all top-level Decls. + + this->~NamespaceDecl(); + C.Deallocate((void *)this); +} + + +ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, QualType T) { + return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T); +} + +FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName N, QualType T, + TypeSourceInfo *TInfo, + StorageClass S, bool isInline, + bool hasWrittenPrototype) { + FunctionDecl *New + = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline); + New->HasWrittenPrototype = hasWrittenPrototype; + return New; +} + +BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { + return new (C) BlockDecl(DC, L); +} + +EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, + SourceLocation L, + IdentifierInfo *Id, QualType T, + Expr *E, const llvm::APSInt &V) { + return new (C) EnumConstantDecl(CD, L, Id, T, E, V); +} + +void EnumConstantDecl::Destroy(ASTContext& C) { + if (Init) Init->Destroy(C); + Decl::Destroy(C); +} + +TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + TypeSourceInfo *TInfo) { + return new (C) TypedefDecl(DC, L, Id, TInfo); +} + +// Anchor TypedefDecl's vtable here. +TypedefDecl::~TypedefDecl() {} + +FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + StringLiteral *Str) { + return new (C) FileScopeAsmDecl(DC, L, Str); +} diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 84aa81ca76db..863a1cbd03c4 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -448,7 +448,10 @@ bool DeclContext::classof(const Decl *D) { } DeclContext::~DeclContext() { - delete static_cast<StoredDeclsMap*>(LookupPtr); + // 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); } void DeclContext::DestroyDecls(ASTContext &C) { @@ -622,7 +625,8 @@ 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 = new StoredDeclsMap; + StoredDeclsMap *Map = + (StoredDeclsMap*) getParentASTContext().CreateStoredDeclsMap(); LookupPtr = Map; for (unsigned I = 0, N = Decls.size(); I != N; ++I) { (*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations); @@ -830,8 +834,11 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { if (isa<ClassTemplateSpecializationDecl>(D)) return; - if (!LookupPtr) - LookupPtr = new StoredDeclsMap; + ASTContext *C = 0; + if (!LookupPtr) { + C = &getParentASTContext(); + LookupPtr = (StoredDeclsMap*) C->CreateStoredDeclsMap(); + } // Insert this declaration into the map. StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr); @@ -844,7 +851,10 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { // If it is possible that this is a redeclaration, check to see if there is // already a decl for which declarationReplaces returns true. If there is // one, just replace it and return. - if (DeclNameEntries.HandleRedeclaration(getParentASTContext(), D)) + if (!C) + C = &getParentASTContext(); + + if (DeclNameEntries.HandleRedeclaration(*C, D)) return; // Put this declaration into the appropriate slot. @@ -896,3 +906,18 @@ void StoredDeclsList::materializeDecls(ASTContext &Context) { } } } + +//===----------------------------------------------------------------------===// +// Creation and Destruction of StoredDeclsMaps. // +//===----------------------------------------------------------------------===// + +void *ASTContext::CreateStoredDeclsMap() { + StoredDeclsMap *M = new StoredDeclsMap(); + SDMs.push_back(M); + return M; +} + +void ASTContext::ReleaseDeclContextMaps() { + for (std::vector<void*>::iterator I = SDMs.begin(), E = SDMs.end(); I!=E; ++I) + delete (StoredDeclsMap*) *I; +} diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index fe6064df325a..b0569d68015f 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -25,18 +25,23 @@ using namespace clang; // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// -CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - CXXRecordDecl *PrevDecl, - SourceLocation TKL) - : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL), - UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), +CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) + : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), Abstract(false), HasTrivialConstructor(true), HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), HasTrivialDestructor(true), ComputedVisibleConversions(false), Bases(0), NumBases(0), VBases(0), NumVBases(0), + Definition(D) { +} + +CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + CXXRecordDecl *PrevDecl, + SourceLocation TKL) + : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL), + DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0), TemplateOrInstantiation() { } CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, @@ -57,31 +62,35 @@ CXXRecordDecl::~CXXRecordDecl() { } void CXXRecordDecl::Destroy(ASTContext &C) { - C.Deallocate(Bases); - C.Deallocate(VBases); + if (data().Definition == this) { + C.Deallocate(data().Bases); + C.Deallocate(data().VBases); + C.Deallocate(&data()); + } this->RecordDecl::Destroy(C); } void -CXXRecordDecl::setBases(ASTContext &C, - CXXBaseSpecifier const * const *Bases, +CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { + ASTContext &C = getASTContext(); + // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] // no base classes [...]. - Aggregate = false; + data().Aggregate = false; - if (this->Bases) - C.Deallocate(this->Bases); + if (data().Bases) + C.Deallocate(data().Bases); int vbaseCount = 0; llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases; bool hasDirectVirtualBase = false; - this->Bases = new(C) CXXBaseSpecifier [NumBases]; - this->NumBases = NumBases; + data().Bases = new(C) CXXBaseSpecifier [NumBases]; + data().NumBases = NumBases; for (unsigned i = 0; i < NumBases; ++i) { - this->Bases[i] = *Bases[i]; + data().Bases[i] = *Bases[i]; // Keep track of inherited vbases for this base class. const CXXBaseSpecifier *Base = Bases[i]; QualType BaseType = Base->getType(); @@ -130,13 +139,13 @@ CXXRecordDecl::setBases(ASTContext &C, } if (vbaseCount > 0) { // build AST for inhireted, direct or indirect, virtual bases. - this->VBases = new (C) CXXBaseSpecifier [vbaseCount]; - this->NumVBases = vbaseCount; + data().VBases = new (C) CXXBaseSpecifier [vbaseCount]; + data().NumVBases = vbaseCount; for (int i = 0; i < vbaseCount; i++) { QualType QT = UniqueVbases[i]->getType(); CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl()); - this->VBases[i] = + data().VBases[i] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, VBaseClassDecl->getTagKind() == RecordDecl::TK_class, UniqueVbases[i]->getAccessSpecifier(), QT); @@ -239,32 +248,32 @@ CXXRecordDecl::addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl) { assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl"); // Note that we have a user-declared constructor. - UserDeclaredConstructor = true; + data().UserDeclaredConstructor = true; // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with no // user-declared constructors (12.1) [...]. - Aggregate = false; + data().Aggregate = false; // C++ [class]p4: // A POD-struct is an aggregate class [...] - PlainOldData = false; + data().PlainOldData = false; // C++ [class.ctor]p5: // A constructor is trivial if it is an implicitly-declared default // constructor. // FIXME: C++0x: don't do this for "= default" default constructors. - HasTrivialConstructor = false; + data().HasTrivialConstructor = false; // Note when we have a user-declared copy constructor, which will // suppress the implicit declaration of a copy constructor. if (ConDecl->isCopyConstructor()) { - UserDeclaredCopyConstructor = true; + data().UserDeclaredCopyConstructor = true; // C++ [class.copy]p6: // A copy constructor is trivial if it is implicitly declared. // FIXME: C++0x: don't do this for "= default" copy constructors. - HasTrivialCopyConstructor = false; + data().HasTrivialCopyConstructor = false; } } @@ -295,17 +304,17 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, OpDecl->setCopyAssignment(true); // Suppress the implicit declaration of a copy constructor. - UserDeclaredCopyAssignment = true; + data().UserDeclaredCopyAssignment = true; // C++ [class.copy]p11: // A copy assignment operator is trivial if it is implicitly declared. // FIXME: C++0x: don't do this for "= default" copy operators. - HasTrivialCopyAssignment = false; + data().HasTrivialCopyAssignment = false; // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. - PlainOldData = false; + data().PlainOldData = false; } void @@ -415,42 +424,42 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { // If root class, all conversions are visible. if (bases_begin() == bases_end()) - return &Conversions; + return &data().Conversions; // If visible conversion list is already evaluated, return it. - if (ComputedVisibleConversions) - return &VisibleConversions; + if (data().ComputedVisibleConversions) + return &data().VisibleConversions; llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet; collectConversionFunctions(TopConversionsTypeSet); getNestedVisibleConversionFunctions(this, TopConversionsTypeSet, TopConversionsTypeSet); - ComputedVisibleConversions = true; - return &VisibleConversions; + data().ComputedVisibleConversions = true; + return &data().VisibleConversions; } void CXXRecordDecl::addVisibleConversionFunction( CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - VisibleConversions.addDecl(ConvDecl); + data().VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addVisibleConversionFunction( FunctionTemplateDecl *ConvDecl) { assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - VisibleConversions.addDecl(ConvDecl); + data().VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - Conversions.addDecl(ConvDecl); + data().Conversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - Conversions.addDecl(ConvDecl); + data().Conversions.addDecl(ConvDecl); } @@ -579,7 +588,8 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { // then this function is a usual deallocation function. ASTContext &Context = getASTContext(); if (getNumParams() != 2 || - !Context.hasSameType(getParamDecl(1)->getType(), Context.getSizeType())) + !Context.hasSameUnqualifiedType(getParamDecl(1)->getType(), + Context.getSizeType())) return false; // This function is a usual deallocation function if there are no @@ -604,7 +614,9 @@ static OverriddenMethodsMapTy *OverriddenMethods = 0; void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { assert(MD->isCanonicalDecl() && "Method is not canonical!"); - + assert(!MD->getParent()->isDependentContext() && + "Can't add an overridden method to a class template!"); + // FIXME: The CXXMethodDecl dtor needs to remove and free the entry. if (!OverriddenMethods) @@ -671,42 +683,25 @@ bool CXXMethodDecl::hasInlineBody() const { CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, CXXConstructorDecl *C, - SourceLocation L, - Expr **Args, unsigned NumArgs, - SourceLocation R) - : BaseOrMember(TInfo), Args(0), NumArgs(0), CtorOrAnonUnion(C), + TypeSourceInfo *TInfo, + SourceLocation L, Expr *Init, SourceLocation R) + : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), LParenLoc(L), RParenLoc(R) { - if (NumArgs > 0) { - this->NumArgs = NumArgs; - this->Args = new (Context) Stmt*[NumArgs]; - for (unsigned Idx = 0; Idx < NumArgs; ++Idx) - this->Args[Idx] = Args[Idx]; - } } CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, - CXXConstructorDecl *C, SourceLocation L, - Expr **Args, unsigned NumArgs, - SourceLocation R) - : BaseOrMember(Member), MemberLocation(MemberLoc), Args(0), NumArgs(0), - CtorOrAnonUnion(C), LParenLoc(L), RParenLoc(R) + SourceLocation L, Expr *Init, SourceLocation R) + : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init), + AnonUnionMember(0), LParenLoc(L), RParenLoc(R) { - if (NumArgs > 0) { - this->NumArgs = NumArgs; - this->Args = new (Context) Stmt*[NumArgs]; - for (unsigned Idx = 0; Idx < NumArgs; ++Idx) - this->Args[Idx] = Args[Idx]; - } } void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) { - for (unsigned I = 0; I != NumArgs; ++I) - Args[I]->Destroy(Context); - Context.Deallocate(Args); + if (Init) + Init->Destroy(Context); this->~CXXBaseOrMemberInitializer(); } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index ffda505aaab1..131e098d0467 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -111,8 +111,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { // Look through categories. for (ObjCCategoryDecl *Category = OID->getCategoryList(); Category; Category = Category->getNextClassCategory()) { - if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId)) - return P; + if (!Category->IsClassExtension()) + if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId)) + return P; } // Look through protocols. for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), @@ -124,10 +125,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return OID->getSuperClass()->FindPropertyDeclaration(PropertyId); } else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) { // Look through protocols. - for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(), - E = OCD->protocol_end(); I != E; ++I) { - if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) - return P; + if (!OCD->IsClassExtension()) + for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(), + E = OCD->protocol_end(); I != E; ++I) { + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; } } return 0; diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 32ac53d85be8..a625865ecdb3 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -403,32 +404,51 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { CXXBaseOrMemberInitializer * BMInitializer = (*B); if (B != CDecl->init_begin()) Out << ", "; - bool hasArguments = (BMInitializer->arg_begin() != - BMInitializer->arg_end()); if (BMInitializer->isMemberInitializer()) { FieldDecl *FD = BMInitializer->getMember(); Out << FD->getNameAsString(); + } else { + Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(); } - else // FIXME. skip dependent types for now. - if (const RecordType *RT = - BMInitializer->getBaseClass()->getAs<RecordType>()) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(RT->getDecl()); - Out << BaseDecl->getNameAsString(); - } - if (hasArguments) { - Out << "("; - for (CXXBaseOrMemberInitializer::const_arg_iterator BE = - BMInitializer->const_arg_begin(), - EE = BMInitializer->const_arg_end(); BE != EE; ++BE) { - if (BE != BMInitializer->const_arg_begin()) - Out<< ", "; - const Expr *Exp = (*BE); - Exp->printPretty(Out, Context, 0, Policy, Indentation); + + Out << "("; + if (!BMInitializer->getInit()) { + // Nothing to print + } else { + Expr *Init = BMInitializer->getInit(); + if (CXXExprWithTemporaries *Tmp + = dyn_cast<CXXExprWithTemporaries>(Init)) + Init = Tmp->getSubExpr(); + + Init = Init->IgnoreParens(); + + Expr *SimpleInit = 0; + Expr **Args = 0; + unsigned NumArgs = 0; + if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } else if (CXXConstructExpr *Construct + = dyn_cast<CXXConstructExpr>(Init)) { + Args = Construct->getArgs(); + NumArgs = Construct->getNumArgs(); + } else + SimpleInit = Init; + + if (SimpleInit) + SimpleInit->printPretty(Out, Context, 0, Policy, Indentation); + else { + for (unsigned I = 0; I != NumArgs; ++I) { + if (isa<CXXDefaultArgExpr>(Args[I])) + break; + + if (I) + Out << ", "; + Args[I]->printPretty(Out, Context, 0, Policy, Indentation); + } } - Out << ")"; - } else - Out << "()"; + } + Out << ")"; } } } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 75b3975322b2..d80db45f4557 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -213,7 +213,8 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { TemplateArgs.push_back(TemplateArgument(ParamType)); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), + Expr *E = new (Context) DeclRefExpr(NTTP, + NTTP->getType().getNonReferenceType(), NTTP->getLocation()); TemplateArgs.push_back(TemplateArgument(E)); } else { diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index ff810735bc81..19b58bcbaf03 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -66,27 +66,33 @@ public: } }; -bool operator<(DeclarationName LHS, DeclarationName RHS) { +static int compareInt(unsigned A, unsigned B) { + return (A < B ? -1 : (A > B ? 1 : 0)); +} + +int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { if (LHS.getNameKind() != RHS.getNameKind()) - return LHS.getNameKind() < RHS.getNameKind(); + return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1); switch (LHS.getNameKind()) { - case DeclarationName::Identifier: - return LHS.getAsIdentifierInfo()->getName() < - RHS.getAsIdentifierInfo()->getName(); + case DeclarationName::Identifier: { + IdentifierInfo *LII = LHS.getAsIdentifierInfo(); + IdentifierInfo *RII = RHS.getAsIdentifierInfo(); + if (!LII) return RII ? -1 : 0; + if (!RII) return 1; + + return LII->getName().compare(RII->getName()); + } case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: { Selector LHSSelector = LHS.getObjCSelector(); Selector RHSSelector = RHS.getObjCSelector(); - for (unsigned I = 0, - N = std::min(LHSSelector.getNumArgs(), RHSSelector.getNumArgs()); - I != N; ++I) { + unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs(); + for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) { IdentifierInfo *LHSId = LHSSelector.getIdentifierInfoForSlot(I); IdentifierInfo *RHSId = RHSSelector.getIdentifierInfoForSlot(I); - if (!LHSId || !RHSId) - return LHSId && !RHSId; switch (LHSId->getName().compare(RHSId->getName())) { case -1: return true; @@ -94,27 +100,32 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) { default: break; } } - - return LHSSelector.getNumArgs() < RHSSelector.getNumArgs(); + + return compareInt(LN, RN); } case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: - return QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType()); + if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType())) + return -1; + if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType())) + return 1; + return 0; case DeclarationName::CXXOperatorName: - return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator(); + return compareInt(LHS.getCXXOverloadedOperator(), + RHS.getCXXOverloadedOperator()); case DeclarationName::CXXLiteralOperatorName: - return LHS.getCXXLiteralIdentifier()->getName() < - RHS.getCXXLiteralIdentifier()->getName(); + return LHS.getCXXLiteralIdentifier()->getName().compare( + RHS.getCXXLiteralIdentifier()->getName()); case DeclarationName::CXXUsingDirective: - return false; + return 0; } - return false; + return 0; } } // end namespace clang diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index fa44b510e99a..4cb0aa4560de 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -99,8 +99,7 @@ void DeclRefExpr::computeDependence() { else if (VarDecl *Var = dyn_cast<VarDecl>(D)) { if (Var->getType()->isIntegralType() && Var->getType().getCVRQualifiers() == Qualifiers::Const) { - const VarDecl *Def = 0; - if (const Expr *Init = Var->getDefinition(Def)) + if (const Expr *Init = Var->getAnyInitializer()) if (Init->isValueDependent()) ValueDependent = true; } @@ -164,17 +163,18 @@ SourceRange DeclRefExpr::getSourceRange() const { // FIXME: Maybe this should use DeclPrinter with a special "print predefined // expr" policy instead. -std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT, - const Decl *CurrentDecl) { +std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { + ASTContext &Context = CurrentDecl->getASTContext(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) { - if (IT != PrettyFunction) + if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual) return FD->getNameAsString(); llvm::SmallString<256> Name; llvm::raw_svector_ostream Out(Name); if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - if (MD->isVirtual()) + if (MD->isVirtual() && IT != PrettyFunctionNoVirtual) Out << "virtual "; if (MD->isStatic()) Out << "static "; @@ -827,9 +827,17 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case BinaryOperatorClass: { const BinaryOperator *BO = cast<BinaryOperator>(this); // Consider comma to have side effects if the LHS or RHS does. - if (BO->getOpcode() == BinaryOperator::Comma) + if (BO->getOpcode() == BinaryOperator::Comma) { + // ((foo = <blah>), 0) is an idiom for hiding the result (and + // lvalue-ness) of an assignment written in a macro. + if (IntegerLiteral *IE = + dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens())) + if (IE->getValue() == 0) + return false; + return (BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + } if (BO->isAssignmentOp()) return false; @@ -1068,9 +1076,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { if (isa<FieldDecl>(Member)) { if (m->isArrow()) return LV_Valid; - Expr *BaseExp = m->getBase(); - return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ? - LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx); + return m->getBase()->isLvalue(Ctx); } // -- If it refers to a static member function [...], then @@ -1093,8 +1099,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { if (m->isArrow()) return LV_Valid; Expr *BaseExp = m->getBase(); - return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ? - LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx); + if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) + return LV_SubObjCPropertySetting; + return + (BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass) ? + LV_SubObjCPropertyGetterSetting : BaseExp->isLvalue(Ctx); } case UnaryOperatorClass: if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref) @@ -1205,6 +1214,9 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { case CXXBindTemporaryExprClass: return cast<CXXBindTemporaryExpr>(this)->getSubExpr()-> isLvalueInternal(Ctx); + case CXXBindReferenceExprClass: + // Something that's bound to a reference is always an lvalue. + return LV_Valid; case ConditionalOperatorClass: { // Complicated handling is only for C++. if (!Ctx.getLangOptions().CPlusPlus) @@ -1281,7 +1293,9 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { } return MLV_InvalidExpression; case LV_MemberFunction: return MLV_MemberFunction; - case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; + case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; + case LV_SubObjCPropertyGetterSetting: + return MLV_SubObjCPropertyGetterSetting; } // The following is illegal: @@ -1594,6 +1608,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: case Expr::CXXBindTemporaryExprClass: + case Expr::CXXBindReferenceExprClass: case Expr::CXXExprWithTemporariesClass: case Expr::CXXTemporaryObjectExprClass: case Expr::CXXUnresolvedConstructExprClass: @@ -1613,7 +1628,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::BlockExprClass: case Expr::BlockDeclRefExprClass: case Expr::NoStmtClass: - case Expr::ExprClass: return ICEDiag(2, E->getLocStart()); case Expr::GNUNullExprClass: @@ -1650,30 +1664,22 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { if (Quals.hasVolatile() || !Quals.hasConst()) return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); - // Look for the definition of this variable, which will actually have - // an initializer. - const VarDecl *Def = 0; - const Expr *Init = Dcl->getDefinition(Def); + // Look for a declaration of this variable that has an initializer. + const VarDecl *ID = 0; + const Expr *Init = Dcl->getAnyInitializer(ID); if (Init) { - if (Def->isInitKnownICE()) { + if (ID->isInitKnownICE()) { // We have already checked whether this subexpression is an // integral constant expression. - if (Def->isInitICE()) + if (ID->isInitICE()) return NoDiag(); else return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); } - // C++ [class.static.data]p4: - // If a static data member is of const integral or const - // enumeration type, its declaration in the class definition can - // specify a constant-initializer which shall be an integral - // constant expression (5.19). In that case, the member can appear - // in integral constant expressions. - if (Def->isOutOfLine()) { - Dcl->setInitKnownICE(false); - return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); - } + // It's an ICE whether or not the definition we found is + // out-of-line. See DR 721 and the discussion in Clang PR + // 6206 for details. if (Dcl->isCheckingICE()) { return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); @@ -1810,9 +1816,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } } } - case Expr::CastExprClass: case Expr::ImplicitCastExprClass: - case Expr::ExplicitCastExprClass: case Expr::CStyleCastExprClass: case Expr::CXXFunctionalCastExprClass: case Expr::CXXNamedCastExprClass: @@ -1954,6 +1958,13 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx, FieldDecl *Expr::getBitField() { Expr *E = this->IgnoreParens(); + while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp) + E = ICE->getSubExpr()->IgnoreParens(); + else + break; + } + if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E)) if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl())) if (Field->isBitField()) @@ -1966,6 +1977,25 @@ FieldDecl *Expr::getBitField() { return 0; } +bool Expr::refersToVectorElement() const { + const Expr *E = this->IgnoreParens(); + + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp) + E = ICE->getSubExpr()->IgnoreParens(); + else + break; + } + + if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) + return ASE->getBase()->getType()->isVectorType(); + + if (isa<ExtVectorElementExpr>(E)) + return true; + + return false; +} + /// isArrow - Return true if the base expression is a pointer to vector, /// return false if the base expression is a vector. bool ExtVectorElementExpr::isArrow() const { @@ -2030,14 +2060,15 @@ void ExtVectorElementExpr::getEncodedElementAccess( } // constructor for instance messages. -ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) +ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver, + Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; - SubExprs = new Stmt*[NumArgs+1]; + SubExprs = new (C) Stmt*[NumArgs+1]; SubExprs[RECEIVER] = receiver; if (NumArgs) { for (unsigned i = 0; i != NumArgs; ++i) @@ -2049,14 +2080,15 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, // constructor for class messages. // FIXME: clsName should be typed to ObjCInterfaceType -ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) +ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, + Selector selInfo, QualType retType, + ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; - SubExprs = new Stmt*[NumArgs+1]; + SubExprs = new (C) Stmt*[NumArgs+1]; SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown); if (NumArgs) { for (unsigned i = 0; i != NumArgs; ++i) @@ -2067,14 +2099,15 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, } // constructor for class messages. -ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) +ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, + Selector selInfo, QualType retType, + ObjCMethodDecl *mproto, SourceLocation LBrac, + SourceLocation RBrac, Expr **ArgExprs, + unsigned nargs) : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; - SubExprs = new Stmt*[NumArgs+1]; + SubExprs = new (C) Stmt*[NumArgs+1]; SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown); if (NumArgs) { for (unsigned i = 0; i != NumArgs; ++i) @@ -2109,6 +2142,13 @@ void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) { SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.first | IsClsMethDeclKnown); } +void ObjCMessageExpr::DoDestroy(ASTContext &C) { + DestroyChildren(C); + if (SubExprs) + C.Deallocate(SubExprs); + this->~ObjCMessageExpr(); + C.Deallocate((void*) this); +} bool ChooseExpr::isConditionTrue(ASTContext &C) const { return getCond()->EvaluateAsInt(C) != 0; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index a6574efda8ee..f4b8333dd3ae 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -73,7 +73,7 @@ Stmt::child_iterator CXXZeroInitValueExpr::child_end() { } // CXXNewExpr -CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, +CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, unsigned numPlaceArgs, bool parenTypeId, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, @@ -87,7 +87,7 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, OperatorDelete(operatorDelete), Constructor(constructor), StartLoc(startLoc), EndLoc(endLoc) { unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; - SubExprs = new Stmt*[TotalSize]; + SubExprs = new (C) Stmt*[TotalSize]; unsigned i = 0; if (Array) SubExprs[i++] = arraySize; @@ -98,6 +98,14 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, assert(i == TotalSize); } +void CXXNewExpr::DoDestroy(ASTContext &C) { + DestroyChildren(C); + if (SubExprs) + C.Deallocate(SubExprs); + this->~CXXNewExpr(); + C.Deallocate((void*)this); +} + Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; } Stmt::child_iterator CXXNewExpr::child_end() { return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs(); @@ -116,6 +124,7 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { // UnresolvedLookupExpr UnresolvedLookupExpr * UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, + CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, DeclarationName Name, SourceLocation NameLoc, bool ADL, @@ -125,7 +134,8 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, ExplicitTemplateArgumentList::sizeFor(Args)); UnresolvedLookupExpr *ULE = new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, - Dependent, Qualifier, QualifierRange, + Dependent, NamingClass, + Qualifier, QualifierRange, Name, NameLoc, ADL, /*Overload*/ true, /*ExplicitTemplateArgs*/ true); @@ -135,10 +145,9 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, return ULE; } -bool UnresolvedLookupExpr:: - ComputeDependence(UnresolvedSetImpl::const_iterator Begin, - UnresolvedSetImpl::const_iterator End, - const TemplateArgumentListInfo *Args) { +bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin, + UnresolvedSetIterator End, + const TemplateArgumentListInfo *Args) { for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I) if ((*I)->getDeclContext()->isDependentContext()) return true; @@ -393,6 +402,19 @@ void CXXBindTemporaryExpr::DoDestroy(ASTContext &C) { C.Deallocate(this); } +CXXBindReferenceExpr *CXXBindReferenceExpr::Create(ASTContext &C, Expr *SubExpr, + bool ExtendsLifetime, + bool RequiresTemporaryCopy) { + return new (C) CXXBindReferenceExpr(SubExpr, + ExtendsLifetime, + RequiresTemporaryCopy); +} + +void CXXBindReferenceExpr::DoDestroy(ASTContext &C) { + this->~CXXBindReferenceExpr(); + C.Deallocate(this); +} + CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, QualType writtenTy, @@ -409,22 +431,26 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, - bool ZeroInitialization) { + bool ZeroInitialization, + bool BaseInitialization) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, - Elidable, Args, NumArgs, ZeroInitialization); + Elidable, Args, NumArgs, ZeroInitialization, + BaseInitialization); } CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, - bool ZeroInitialization) + bool ZeroInitialization, + bool BaseInitialization) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), Constructor(D), Loc(Loc), Elidable(elidable), - ZeroInitialization(ZeroInitialization), Args(0), NumArgs(numargs) + ZeroInitialization(ZeroInitialization), + BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs) { if (NumArgs) { Args = new (C) Stmt*[NumArgs]; @@ -491,6 +517,15 @@ Stmt::child_iterator CXXBindTemporaryExpr::child_end() { return &SubExpr + 1; } +// CXXBindReferenceExpr +Stmt::child_iterator CXXBindReferenceExpr::child_begin() { + return &SubExpr; +} + +Stmt::child_iterator CXXBindReferenceExpr::child_end() { + return &SubExpr + 1; +} + // CXXConstructExpr Stmt::child_iterator CXXConstructExpr::child_begin() { return &Args[0]; @@ -618,15 +653,13 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, DeclarationName MemberName, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) - : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent), - Base(Base), BaseType(BaseType), IsArrow(IsArrow), - HasUnresolvedUsing(HasUnresolvedUsing), - HasExplicitTemplateArgs(TemplateArgs != 0), - OperatorLoc(OperatorLoc), - Qualifier(Qualifier), QualifierRange(QualifierRange), - MemberName(MemberName), MemberLoc(MemberLoc) { + : OverloadExpr(UnresolvedMemberExprClass, T, Dependent, + Qualifier, QualifierRange, MemberName, MemberLoc, + TemplateArgs != 0), + IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), + Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { if (TemplateArgs) - getExplicitTemplateArgs()->initializeFrom(*TemplateArgs); + getExplicitTemplateArgs().initializeFrom(*TemplateArgs); } UnresolvedMemberExpr * @@ -651,6 +684,35 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, Member, MemberLoc, TemplateArgs); } +CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { + // Unlike for UnresolvedLookupExpr, it is very easy to re-derive this. + + // If there was a nested name specifier, it names the naming class. + // It can't be dependent: after all, we were actually able to do the + // lookup. + const RecordType *RT; + if (getQualifier()) { + Type *T = getQualifier()->getAsType(); + assert(T && "qualifier in member expression does not name type"); + RT = T->getAs<RecordType>(); + assert(RT && "qualifier in member expression does not name record"); + + // Otherwise the naming class must have been the base class. + } else { + QualType BaseType = getBaseType().getNonReferenceType(); + if (isArrow()) { + const PointerType *PT = BaseType->getAs<PointerType>(); + assert(PT && "base of arrow member access is not pointer"); + BaseType = PT->getPointeeType(); + } + + RT = BaseType->getAs<RecordType>(); + assert(RT && "base of member expression does not name record"); + } + + return cast<CXXRecordDecl>(RT->getDecl()); +} + Stmt::child_iterator UnresolvedMemberExpr::child_begin() { return child_iterator(&Base); } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 086249c811f9..1a44cd02d9c1 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -263,8 +263,7 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { if (!VD->getType()->isReferenceType()) return APValue(E); // FIXME: Check whether VD might be overridden! - const VarDecl *Def = 0; - if (const Expr *Init = VD->getDefinition(Def)) + if (const Expr *Init = VD->getAnyInitializer()) return Visit(const_cast<Expr *>(Init)); } @@ -813,7 +812,7 @@ public: return false; } - bool VisitCallExpr(const CallExpr *E); + bool VisitCallExpr(CallExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitConditionalOperator(const ConditionalOperator *E); @@ -849,8 +848,8 @@ public: bool VisitUnaryImag(const UnaryOperator *E); private: - unsigned GetAlignOfExpr(const Expr *E); - unsigned GetAlignOfType(QualType T); + CharUnits GetAlignOfExpr(const Expr *E); + CharUnits GetAlignOfType(QualType T); // FIXME: Missing: array subscript of vector, member of vector }; } // end anonymous namespace @@ -879,9 +878,12 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { // In C, they can also be folded, although they are not ICEs. if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers() == Qualifiers::Const) { + + if (isa<ParmVarDecl>(D)) + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - const VarDecl *Def = 0; - if (const Expr *Init = VD->getDefinition(Def)) { + if (const Expr *Init = VD->getAnyInitializer()) { if (APValue *V = VD->getEvaluatedValue()) { if (V->isInt()) return Success(V->getInt(), E); @@ -965,7 +967,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { return -1; } -bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { +bool IntExprEvaluator::VisitCallExpr(CallExpr *E) { switch (E->isBuiltinCall(Info.Ctx)) { default: return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); @@ -1020,6 +1022,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand); return Success(Operand, E); } + + case Builtin::BI__builtin_expect: + return Visit(E->getArg(0)); } } @@ -1288,7 +1293,7 @@ bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr()); } -unsigned IntExprEvaluator::GetAlignOfType(QualType T) { +CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, // the result is the size of the referenced type." // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the @@ -1300,20 +1305,22 @@ unsigned IntExprEvaluator::GetAlignOfType(QualType T) { unsigned CharSize = Info.Ctx.Target.getCharWidth(); // __alignof is defined to return the preferred alignment. - return Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize; + return CharUnits::fromQuantity( + Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize); } -unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) { +CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) { E = E->IgnoreParens(); // alignof decl is always accepted, even if it doesn't make sense: we default // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true); + return Info.Ctx.getDeclAlign(DRE->getDecl(), + /*RefAsPointee*/true); if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) - return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl(), - /*RefAsPointee*/true); + return Info.Ctx.getDeclAlign(ME->getMemberDecl(), + /*RefAsPointee*/true); return GetAlignOfType(E->getType()); } @@ -1325,9 +1332,9 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { // Handle alignof separately. if (!E->isSizeOf()) { if (E->isArgumentType()) - return Success(GetAlignOfType(E->getArgumentType()), E); + return Success(GetAlignOfType(E->getArgumentType()).getQuantity(), E); else - return Success(GetAlignOfExpr(E->getArgumentExpr()), E); + return Success(GetAlignOfExpr(E->getArgumentExpr()).getQuantity(), E); } QualType SrcTy = E->getTypeOfArgument(); diff --git a/lib/AST/Makefile b/lib/AST/Makefile index f7d4e9f62d5f..8afc629d6b3b 100644 --- a/lib/AST/Makefile +++ b/lib/AST/Makefile @@ -14,7 +14,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangAST BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 0aa01801959c..50acd15fde05 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -119,11 +119,10 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, return; } } - if (i->isVirtual()) { - SelectPrimaryVBase(Base, FirstPrimary); - if (PrimaryBase.getBase()) - return; - } + assert(i->isVirtual()); + SelectPrimaryVBase(Base, FirstPrimary); + if (PrimaryBase.getBase()) + return; } } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 104e3361892f..8347249a466b 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -35,6 +35,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { // Intialize the table on the first use. Initialized = true; +#define ABSTRACT_EXPR(CLASS, PARENT) #define STMT(CLASS, PARENT) \ StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \ StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS); @@ -132,9 +133,8 @@ Expr *AsmStmt::getOutputExpr(unsigned i) { /// getOutputConstraint - Return the constraint string for the specified /// output operand. All output constraints are known to be non-empty (either /// '=' or '+'). -std::string AsmStmt::getOutputConstraint(unsigned i) const { - return std::string(Constraints[i]->getStrData(), - Constraints[i]->getByteLength()); +llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const { + return getOutputConstraintLiteral(i)->getString(); } /// getNumPlusOperands - Return the number of output operands that have a "+" @@ -147,40 +147,52 @@ unsigned AsmStmt::getNumPlusOperands() const { return Res; } - - Expr *AsmStmt::getInputExpr(unsigned i) { return cast<Expr>(Exprs[i + NumOutputs]); } /// getInputConstraint - Return the specified input constraint. Unlike output /// constraints, these can be empty. -std::string AsmStmt::getInputConstraint(unsigned i) const { - return std::string(Constraints[i + NumOutputs]->getStrData(), - Constraints[i + NumOutputs]->getByteLength()); +llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const { + return getInputConstraintLiteral(i)->getString(); } -void AsmStmt::setOutputsAndInputs(unsigned NumOutputs, - unsigned NumInputs, - const std::string *Names, - StringLiteral **Constraints, - Stmt **Exprs) { +void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, + IdentifierInfo **Names, + StringLiteral **Constraints, + Stmt **Exprs, + unsigned NumOutputs, + unsigned NumInputs, + StringLiteral **Clobbers, + unsigned NumClobbers) { this->NumOutputs = NumOutputs; this->NumInputs = NumInputs; - this->Names.clear(); - this->Names.insert(this->Names.end(), Names, Names + NumOutputs + NumInputs); - this->Constraints.clear(); - this->Constraints.insert(this->Constraints.end(), - Constraints, Constraints + NumOutputs + NumInputs); - this->Exprs.clear(); - this->Exprs.insert(this->Exprs.end(), Exprs, Exprs + NumOutputs + NumInputs); + this->NumClobbers = NumClobbers; + + unsigned NumExprs = NumOutputs + NumInputs; + + C.Deallocate(this->Names); + this->Names = new (C) IdentifierInfo*[NumExprs]; + std::copy(Names, Names + NumExprs, this->Names); + + C.Deallocate(this->Exprs); + this->Exprs = new (C) Stmt*[NumExprs]; + std::copy(Exprs, Exprs + NumExprs, this->Exprs); + + C.Deallocate(this->Constraints); + this->Constraints = new (C) StringLiteral*[NumExprs]; + std::copy(Constraints, Constraints + NumExprs, this->Constraints); + + C.Deallocate(this->Clobbers); + this->Clobbers = new (C) StringLiteral*[NumClobbers]; + std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers); } /// getNamedOperand - Given a symbolic operand reference like %[foo], /// translate this into a numeric value needed to reference the same operand. /// This returns -1 if the operand name is invalid. -int AsmStmt::getNamedOperand(const std::string &SymbolicName) const { +int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const { unsigned NumPlusOperands = 0; // Check if this is an output operand. @@ -197,11 +209,6 @@ int AsmStmt::getNamedOperand(const std::string &SymbolicName) const { return -1; } -void AsmStmt::setClobbers(StringLiteral **Clobbers, unsigned NumClobbers) { - this->Clobbers.clear(); - this->Clobbers.insert(this->Clobbers.end(), Clobbers, Clobbers + NumClobbers); -} - /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. @@ -313,7 +320,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, if (NameEnd == CurPtr) return diag::err_asm_empty_symbolic_operand_name; - std::string SymbolicName(CurPtr, NameEnd); + llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr); int N = getNamedOperand(SymbolicName); if (N == -1) { @@ -332,26 +339,39 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, } } +QualType CXXCatchStmt::getCaughtType() const { + if (ExceptionDecl) + return ExceptionDecl->getType(); + return QualType(); +} + //===----------------------------------------------------------------------===// // Constructors //===----------------------------------------------------------------------===// -AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, - bool msasm, unsigned numoutputs, unsigned numinputs, - std::string *names, StringLiteral **constraints, +AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, + bool isvolatile, bool msasm, + unsigned numoutputs, unsigned numinputs, + IdentifierInfo **names, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, SourceLocation rparenloc) : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm) - , NumOutputs(numoutputs), NumInputs(numinputs) { - for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) { - Names.push_back(names[i]); - Exprs.push_back(exprs[i]); - Constraints.push_back(constraints[i]); - } + , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { - for (unsigned i = 0; i != numclobbers; i++) - Clobbers.push_back(clobbers[i]); + unsigned NumExprs = NumOutputs +NumInputs; + + Names = new (C) IdentifierInfo*[NumExprs]; + std::copy(names, names + NumExprs, Names); + + Exprs = new (C) Stmt*[NumExprs]; + std::copy(exprs, exprs + NumExprs, Exprs); + + Constraints = new (C) StringLiteral*[NumExprs]; + std::copy(constraints, constraints + NumExprs, Constraints); + + Clobbers = new (C) StringLiteral*[NumClobbers]; + std::copy(clobbers, clobbers + NumClobbers, Clobbers); } ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, @@ -387,6 +407,24 @@ ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, RParenLoc = rparenloc; } +CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, + Stmt *tryBlock, Stmt **handlers, + unsigned numHandlers) { + std::size_t Size = sizeof(CXXTryStmt); + Size += ((numHandlers + 1) * sizeof(Stmt)); + + void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>()); + return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers); +} + +CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, + Stmt **handlers, unsigned numHandlers) + : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) { + Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1); + Stmts[0] = tryBlock; + std::copy(handlers, handlers + NumHandlers, Stmts + 1); +} + //===----------------------------------------------------------------------===// // AST Destruction. //===----------------------------------------------------------------------===// @@ -453,6 +491,18 @@ void WhileStmt::DoDestroy(ASTContext &C) { BranchDestroy(C, this, SubExprs, END_EXPR); } +void AsmStmt::DoDestroy(ASTContext &C) { + DestroyChildren(C); + + C.Deallocate(Names); + C.Deallocate(Constraints); + C.Deallocate(Exprs); + C.Deallocate(Clobbers); + + this->~AsmStmt(); + C.Deallocate((void *)this); +} + //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// @@ -566,10 +616,10 @@ Stmt::child_iterator ReturnStmt::child_end() { // AsmStmt Stmt::child_iterator AsmStmt::child_begin() { - return Exprs.empty() ? 0 : &Exprs[0]; + return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0]; } Stmt::child_iterator AsmStmt::child_end() { - return Exprs.empty() ? 0 : &Exprs[0] + Exprs.size(); + return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0] + NumOutputs + NumInputs; } // ObjCAtCatchStmt @@ -615,19 +665,11 @@ Stmt::child_iterator CXXCatchStmt::child_end() { return &HandlerBlock + 1; } -QualType CXXCatchStmt::getCaughtType() const { - if (ExceptionDecl) - return ExceptionDecl->getType(); - return QualType(); -} - // CXXTryStmt -Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; } -Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); } +Stmt::child_iterator CXXTryStmt::child_begin() { + return reinterpret_cast<Stmt **>(this + 1); +} -CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, - Stmt **handlers, unsigned numHandlers) - : Stmt(CXXTryStmtClass), TryLoc(tryLoc) { - Stmts.push_back(tryBlock); - Stmts.insert(Stmts.end(), handlers, handlers + numHandlers); +Stmt::child_iterator CXXTryStmt::child_end() { + return reinterpret_cast<Stmt **>(this + 1) + NumHandlers + 1; } diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index ae76526b7939..ba6218be1426 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -472,6 +472,8 @@ void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) { DumpExpr(Node); + CXXConstructorDecl *Ctor = Node->getConstructor(); + DumpType(Ctor->getType()); if (Node->isElidable()) OS << " elidable"; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index bbb904de79b3..3ae306d3c7ac 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1038,6 +1038,10 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { PrintExpr(Node->getSubExpr()); } +void StmtPrinter::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *Node) { + PrintExpr(Node->getSubExpr()); +} + void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { OS << Node->getType().getAsString(); OS << "("; diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index b74e1ef0bab4..3a19ec212c14 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -465,6 +465,10 @@ void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) { const_cast<CXXDestructorDecl *>(S->getTemporary()->getDestructor())); } +void StmtProfiler::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) { VisitExpr(S); VisitDecl(S->getConstructor()); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index edfb580cc35f..76cc38292064 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -339,21 +339,18 @@ const RecordType *Type::getAsUnionType() const { return 0; } -ObjCInterfaceType::ObjCInterfaceType(ASTContext &Ctx, QualType Canonical, +ObjCInterfaceType::ObjCInterfaceType(QualType Canonical, ObjCInterfaceDecl *D, ObjCProtocolDecl **Protos, unsigned NumP) : Type(ObjCInterface, Canonical, /*Dependent=*/false), - Decl(D), Protocols(0), NumProtocols(NumP) + Decl(D), NumProtocols(NumP) { - if (NumProtocols) { - Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols]; - memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols)); - } + if (NumProtocols) + memcpy(reinterpret_cast<ObjCProtocolDecl**>(this + 1), Protos, + NumProtocols * sizeof(*Protos)); } void ObjCInterfaceType::Destroy(ASTContext& C) { - if (Protocols) - C.Deallocate(Protocols); this->~ObjCInterfaceType(); C.Deallocate(this); } @@ -372,22 +369,18 @@ bool Type::isObjCQualifiedInterfaceType() const { return getAsObjCQualifiedInterfaceType() != 0; } -ObjCObjectPointerType::ObjCObjectPointerType(ASTContext &Ctx, - QualType Canonical, QualType T, +ObjCObjectPointerType::ObjCObjectPointerType(QualType Canonical, QualType T, ObjCProtocolDecl **Protos, unsigned NumP) : Type(ObjCObjectPointer, Canonical, /*Dependent=*/false), - PointeeType(T), Protocols(NULL), NumProtocols(NumP) + PointeeType(T), NumProtocols(NumP) { - if (NumProtocols) { - Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols]; - memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols)); - } + if (NumProtocols) + memcpy(reinterpret_cast<ObjCProtocolDecl **>(this + 1), Protos, + NumProtocols * sizeof(*Protos)); } void ObjCObjectPointerType::Destroy(ASTContext& C) { - if (Protocols) - C.Deallocate(Protocols); this->~ObjCObjectPointerType(); C.Deallocate(this); } @@ -720,6 +713,19 @@ bool Type::isPromotableIntegerType() const { default: return false; } + + // Enumerated types are promotable to their compatible integer types + // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2). + if (const EnumType *ET = getAs<EnumType>()){ + if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull()) + return false; + + const BuiltinType *BT + = ET->getDecl()->getPromotionType()->getAs<BuiltinType>(); + return BT->getKind() == BuiltinType::Int + || BT->getKind() == BuiltinType::UInt; + } + return false; } @@ -797,12 +803,24 @@ const char *BuiltinType::getName(const LangOptions &LO) const { } } +llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { + switch (CC) { + case CC_Default: llvm_unreachable("no name for default cc"); + default: return ""; + + case CC_C: return "cdecl"; + case CC_X86StdCall: return "stdcall"; + case CC_X86FastCall: return "fastcall"; + } +} + void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, arg_type_iterator ArgTys, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool anyExceptionSpec, unsigned NumExceptions, - exception_iterator Exs, bool NoReturn) { + exception_iterator Exs, bool NoReturn, + CallingConv CallConv) { ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); @@ -815,16 +833,19 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, ID.AddPointer(Exs[i].getAsOpaquePtr()); } ID.AddInteger(NoReturn); + ID.AddInteger(CallConv); } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(), - getNumExceptions(), exception_begin(), getNoReturnAttr()); + getNumExceptions(), exception_begin(), getNoReturnAttr(), + getCallConv()); } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID, - QualType OIT, ObjCProtocolDecl **protocols, + QualType OIT, + ObjCProtocolDecl * const *protocols, unsigned NumProtocols) { ID.AddPointer(OIT.getAsOpaquePtr()); for (unsigned i = 0; i != NumProtocols; i++) @@ -832,10 +853,7 @@ void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID, } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) { - if (getNumProtocols()) - Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols()); - else - Profile(ID, getPointeeType(), 0, 0); + Profile(ID, getPointeeType(), qual_begin(), getNumProtocols()); } /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to @@ -894,8 +912,9 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, E->Profile(ID, Context, true); } -TagType::TagType(TypeClass TC, TagDecl *D, QualType can) - : Type(TC, can, D->isDependentType()), decl(D, 0) {} +TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) + : Type(TC, can, D->isDependentType()), + decl(const_cast<TagDecl*>(D), 0) {} bool RecordType::classof(const TagType *TT) { return isa<RecordDecl>(TT->getDecl()); @@ -1023,7 +1042,7 @@ QualType QualifierCollector::apply(const Type *T) const { void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID, const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **protocols, + ObjCProtocolDecl * const *protocols, unsigned NumProtocols) { ID.AddPointer(Decl); for (unsigned i = 0; i != NumProtocols; i++) @@ -1031,8 +1050,81 @@ void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID, } void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { - if (getNumProtocols()) - Profile(ID, getDecl(), &Protocols[0], getNumProtocols()); - else - Profile(ID, getDecl(), 0, 0); + Profile(ID, getDecl(), qual_begin(), getNumProtocols()); +} + +Linkage Type::getLinkage() const { + // C++ [basic.link]p8: + // Names not covered by these rules have no linkage. + if (this != CanonicalType.getTypePtr()) + return CanonicalType->getLinkage(); + + return NoLinkage; +} + +Linkage BuiltinType::getLinkage() const { + // C++ [basic.link]p8: + // A type is said to have linkage if and only if: + // - it is a fundamental type (3.9.1); or + return ExternalLinkage; +} + +Linkage TagType::getLinkage() const { + // C++ [basic.link]p8: + // - it is a class or enumeration type that is named (or has a name for + // linkage purposes (7.1.3)) and the name has linkage; or + // - it is a specialization of a class template (14); or + return getDecl()->getLinkage(); +} + +// C++ [basic.link]p8: +// - it is a compound type (3.9.2) other than a class or enumeration, +// compounded exclusively from types that have linkage; or +Linkage ComplexType::getLinkage() const { + return ElementType->getLinkage(); +} + +Linkage PointerType::getLinkage() const { + return PointeeType->getLinkage(); +} + +Linkage BlockPointerType::getLinkage() const { + return PointeeType->getLinkage(); +} + +Linkage ReferenceType::getLinkage() const { + return PointeeType->getLinkage(); +} + +Linkage MemberPointerType::getLinkage() const { + return minLinkage(Class->getLinkage(), PointeeType->getLinkage()); +} + +Linkage ArrayType::getLinkage() const { + return ElementType->getLinkage(); +} + +Linkage VectorType::getLinkage() const { + return ElementType->getLinkage(); +} + +Linkage FunctionNoProtoType::getLinkage() const { + return getResultType()->getLinkage(); +} + +Linkage FunctionProtoType::getLinkage() const { + Linkage L = getResultType()->getLinkage(); + for (arg_type_iterator A = arg_type_begin(), AEnd = arg_type_end(); + A != AEnd; ++A) + L = minLinkage(L, (*A)->getLinkage()); + + return L; +} + +Linkage ObjCInterfaceType::getLinkage() const { + return ExternalLinkage; +} + +Linkage ObjCObjectPointerType::getLinkage() const { + return ExternalLinkage; } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 00b74bc21a14..5b621cf7280d 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -225,15 +225,24 @@ void TypePrinter::PrintDependentSizedExtVector( } void TypePrinter::PrintVector(const VectorType *T, std::string &S) { - // FIXME: We prefer to print the size directly here, but have no way - // to get the size of the type. - Print(T->getElementType(), S); - std::string V = "__attribute__((__vector_size__("; - V += llvm::utostr_32(T->getNumElements()); // convert back to bytes. - std::string ET; - Print(T->getElementType(), ET); - V += " * sizeof(" + ET + ")))) "; - S = V + S; + if (T->isAltiVec()) { + if (T->isPixel()) + S = "__vector __pixel " + S; + else { + Print(T->getElementType(), S); + S = "__vector " + S; + } + } else { + // FIXME: We prefer to print the size directly here, but have no way + // to get the size of the type. + Print(T->getElementType(), S); + std::string V = "__attribute__((__vector_size__("; + V += llvm::utostr_32(T->getNumElements()); // convert back to bytes. + std::string ET; + Print(T->getElementType(), ET); + V += " * sizeof(" + ET + ")))) "; + S = V + S; + } } void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) { @@ -271,6 +280,19 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += ")"; + switch(T->getCallConv()) { + case CC_Default: + default: break; + case CC_C: + S += " __attribute__((cdecl))"; + break; + case CC_X86StdCall: + S += " __attribute__((stdcall))"; + break; + case CC_X86FastCall: + S += " __attribute__((fastcall))"; + break; + } if (T->getNoReturnAttr()) S += " __attribute__((noreturn))"; diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index ad9f6dd19413..ccd5088f2ec7 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -12,10 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/AnalysisContext.h" -#include "clang/Analysis/PathSensitive/MemRegion.h" -#include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -87,12 +86,6 @@ AnalysisContext *AnalysisContextManager::getContext(const Decl *D) { return AC; } -const BlockDecl *BlockInvocationContext::getBlockDecl() const { - return Data.is<const BlockDataRegion*>() ? - Data.get<const BlockDataRegion*>()->getDecl() - : Data.get<const BlockDecl*>(); -} - //===----------------------------------------------------------------------===// // FoldingSet profiling. //===----------------------------------------------------------------------===// @@ -117,11 +110,7 @@ void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) { } void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) { - if (const BlockDataRegion *BR = getBlockRegion()) - Profile(ID, getAnalysisContext(), getParent(), BR); - else - Profile(ID, getAnalysisContext(), getParent(), - Data.get<const BlockDecl*>()); + Profile(ID, getAnalysisContext(), getParent(), BD); } //===----------------------------------------------------------------------===// @@ -170,15 +159,6 @@ LocationContextManager::getScope(AnalysisContext *ctx, return getLocationContext<ScopeContext, Stmt>(ctx, parent, s); } -const BlockInvocationContext * -LocationContextManager::getBlockInvocation(AnalysisContext *ctx, - const LocationContext *parent, - const BlockDataRegion *BR) { - return getLocationContext<BlockInvocationContext, BlockDataRegion>(ctx, - parent, - BR); -} - //===----------------------------------------------------------------------===// // LocationContext methods. //===----------------------------------------------------------------------===// @@ -214,6 +194,7 @@ namespace { class FindBlockDeclRefExprsVals : public StmtVisitor<FindBlockDeclRefExprsVals>{ BumpVector<const VarDecl*> &BEVals; BumpVectorContext &BC; + llvm::DenseMap<const VarDecl*, unsigned> Visited; public: FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &bevals, BumpVectorContext &bc) @@ -224,10 +205,27 @@ public: if (Stmt *child = *I) Visit(child); } + + void VisitDeclRefExpr(const DeclRefExpr *DR) { + // Non-local variables are also directly modified. + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) + if (!VD->hasLocalStorage()) { + unsigned &flag = Visited[VD]; + if (!flag) { + flag = 1; + BEVals.push_back(VD, BC); + } + } + } void VisitBlockDeclRefExpr(BlockDeclRefExpr *DR) { - if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) - BEVals.push_back(VD, BC); + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { + unsigned &flag = Visited[VD]; + if (!flag) { + flag = 1; + BEVals.push_back(VD, BC); + } + } } }; } // end anonymous namespace diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 521f1be6ec8b..4f8259e44939 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -2,67 +2,10 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangAnalysis AnalysisContext.cpp - ArrayBoundChecker.cpp - AttrNonNullChecker.cpp - BasicConstraintManager.cpp - BasicObjCFoundationChecks.cpp - BasicStore.cpp - BasicValueFactory.cpp - BugReporter.cpp - BugReporterVisitors.cpp - BuiltinFunctionChecker.cpp CFG.cpp - CFRefCount.cpp - CallAndMessageChecker.cpp - CallInliner.cpp - CastToStructChecker.cpp - CheckDeadStores.cpp - CheckObjCDealloc.cpp - CheckObjCInstMethSignature.cpp - CheckObjCUnusedIVars.cpp - CheckSecuritySyntaxOnly.cpp - CheckSizeofPointer.cpp - Checker.cpp - DereferenceChecker.cpp - DivZeroChecker.cpp - Environment.cpp - ExplodedGraph.cpp - FixedAddressChecker.cpp - GRBlockCounter.cpp - GRCoreEngine.cpp - GRExprEngine.cpp - GRExprEngineExperimentalChecks.cpp - GRState.cpp LiveVariables.cpp - MallocChecker.cpp - ManagerRegistry.cpp - MemRegion.cpp - NoReturnFunctionChecker.cpp - NSAutoreleasePoolChecker.cpp - NSErrorChecker.cpp - OSAtomicChecker.cpp - PathDiagnostic.cpp - PointerArithChecker.cpp - PointerSubChecker.cpp - PthreadLockChecker.cpp - RangeConstraintManager.cpp - RegionStore.cpp - ReturnPointerRangeChecker.cpp - ReturnStackAddressChecker.cpp - ReturnUndefChecker.cpp - SVals.cpp - SValuator.cpp - SimpleConstraintManager.cpp - SimpleSValuator.cpp - Store.cpp - SymbolManager.cpp - UndefBranchChecker.cpp - UndefResultChecker.cpp - UndefinedArraySubscriptChecker.cpp - UndefinedAssignmentChecker.cpp + PrintfFormatString.cpp UninitializedValues.cpp - VLASizeChecker.cpp - ValueManager.cpp ) add_dependencies(clangAnalysis ClangDiagnosticAnalysis) diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 0b2620e609c2..94ed75286dee 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -19,7 +19,7 @@ #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Analysis/FlowSensitive/DataflowSolver.h" #include "clang/Analysis/Support/SaveAndRestore.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/AnalysisContext.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/Analysis/Makefile b/lib/Analysis/Makefile index c597254fd2d7..d6411122e322 100644 --- a/lib/Analysis/Makefile +++ b/lib/Analysis/Makefile @@ -14,7 +14,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangAnalysis BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp new file mode 100644 index 000000000000..55abd1077150 --- /dev/null +++ b/lib/Analysis/PrintfFormatString.cpp @@ -0,0 +1,436 @@ +//= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Handling of format string in printf and friends. The structure of format +// strings for fprintf() are described in C99 7.19.6.1. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/PrintfFormatString.h" +#include "clang/AST/ASTContext.h" + +using clang::analyze_printf::FormatSpecifier; +using clang::analyze_printf::OptionalAmount; +using clang::analyze_printf::ArgTypeResult; +using clang::analyze_printf::FormatStringHandler; +using namespace clang; + +namespace { +class FormatSpecifierResult { + FormatSpecifier FS; + const char *Start; + bool Stop; +public: + FormatSpecifierResult(bool stop = false) + : Start(0), Stop(stop) {} + FormatSpecifierResult(const char *start, + const FormatSpecifier &fs) + : FS(fs), Start(start), Stop(false) {} + + + const char *getStart() const { return Start; } + bool shouldStop() const { return Stop; } + bool hasValue() const { return Start != 0; } + const FormatSpecifier &getValue() const { + assert(hasValue()); + return FS; + } + const FormatSpecifier &getValue() { return FS; } +}; +} // end anonymous namespace + +template <typename T> +class UpdateOnReturn { + T &ValueToUpdate; + const T &ValueToCopy; +public: + UpdateOnReturn(T &valueToUpdate, const T &valueToCopy) + : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {} + + ~UpdateOnReturn() { + ValueToUpdate = ValueToCopy; + } +}; + +//===----------------------------------------------------------------------===// +// Methods for parsing format strings. +//===----------------------------------------------------------------------===// + +static OptionalAmount ParseAmount(const char *&Beg, const char *E) { + const char *I = Beg; + UpdateOnReturn <const char*> UpdateBeg(Beg, I); + + bool foundDigits = false; + unsigned accumulator = 0; + + for ( ; I != E; ++I) { + char c = *I; + if (c >= '0' && c <= '9') { + foundDigits = true; + accumulator += (accumulator * 10) + (c - '0'); + continue; + } + + if (foundDigits) + return OptionalAmount(accumulator, Beg); + + if (c == '*') { + ++I; + return OptionalAmount(OptionalAmount::Arg, Beg); + } + + break; + } + + return OptionalAmount(); +} + +static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, + const char *&Beg, + const char *E) { + + using namespace clang::analyze_printf; + + const char *I = Beg; + const char *Start = 0; + UpdateOnReturn <const char*> UpdateBeg(Beg, I); + + // Look for a '%' character that indicates the start of a format specifier. + for ( ; I != E ; ++I) { + char c = *I; + if (c == '\0') { + // Detect spurious null characters, which are likely errors. + H.HandleNullChar(I); + return true; + } + if (c == '%') { + Start = I++; // Record the start of the format specifier. + break; + } + } + + // No format specifier found? + if (!Start) + return false; + + if (I == E) { + // No more characters left? + H.HandleIncompleteFormatSpecifier(Start, E - Start); + return true; + } + + FormatSpecifier FS; + + // Look for flags (if any). + bool hasMore = true; + for ( ; I != E; ++I) { + switch (*I) { + default: hasMore = false; break; + case '-': FS.setIsLeftJustified(); break; + case '+': FS.setHasPlusPrefix(); break; + case ' ': FS.setHasSpacePrefix(); break; + case '#': FS.setHasAlternativeForm(); break; + case '0': FS.setHasLeadingZeros(); break; + } + if (!hasMore) + break; + } + + if (I == E) { + // No more characters left? + H.HandleIncompleteFormatSpecifier(Start, E - Start); + return true; + } + + // Look for the field width (if any). + FS.setFieldWidth(ParseAmount(I, E)); + + if (I == E) { + // No more characters left? + H.HandleIncompleteFormatSpecifier(Start, E - Start); + return true; + } + + // Look for the precision (if any). + if (*I == '.') { + ++I; + if (I == E) { + H.HandleIncompleteFormatSpecifier(Start, E - Start); + return true; + } + + FS.setPrecision(ParseAmount(I, E)); + + if (I == E) { + // No more characters left? + H.HandleIncompleteFormatSpecifier(Start, E - Start); + return true; + } + } + + // Look for the length modifier. + LengthModifier lm = None; + switch (*I) { + default: + break; + case 'h': + ++I; + lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort; + break; + case 'l': + ++I; + lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong; + break; + case 'j': lm = AsIntMax; ++I; break; + case 'z': lm = AsSizeT; ++I; break; + case 't': lm = AsPtrDiff; ++I; break; + case 'L': lm = AsLongDouble; ++I; break; + case 'q': lm = AsLongLong; ++I; break; + } + FS.setLengthModifier(lm); + + if (I == E) { + // No more characters left? + H.HandleIncompleteFormatSpecifier(Start, E - Start); + return true; + } + + if (*I == '\0') { + // Detect spurious null characters, which are likely errors. + H.HandleNullChar(I); + return true; + } + + // Finally, look for the conversion specifier. + const char *conversionPosition = I++; + ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; + switch (*conversionPosition) { + default: + break; + // C99: 7.19.6.1 (section 8). + case 'd': k = ConversionSpecifier::dArg; break; + case 'i': k = ConversionSpecifier::iArg; break; + case 'o': k = ConversionSpecifier::oArg; break; + case 'u': k = ConversionSpecifier::uArg; break; + case 'x': k = ConversionSpecifier::xArg; break; + case 'X': k = ConversionSpecifier::XArg; break; + case 'f': k = ConversionSpecifier::fArg; break; + case 'F': k = ConversionSpecifier::FArg; break; + case 'e': k = ConversionSpecifier::eArg; break; + case 'E': k = ConversionSpecifier::EArg; break; + case 'g': k = ConversionSpecifier::gArg; break; + case 'G': k = ConversionSpecifier::GArg; break; + case 'a': k = ConversionSpecifier::aArg; break; + case 'A': k = ConversionSpecifier::AArg; break; + case 'c': k = ConversionSpecifier::IntAsCharArg; break; + case 's': k = ConversionSpecifier::CStrArg; break; + case 'p': k = ConversionSpecifier::VoidPtrArg; break; + case 'n': k = ConversionSpecifier::OutIntPtrArg; break; + case '%': k = ConversionSpecifier::PercentArg; break; + // Objective-C. + case '@': k = ConversionSpecifier::ObjCObjArg; break; + // Glibc specific. + case 'm': k = ConversionSpecifier::PrintErrno; break; + } + FS.setConversionSpecifier(ConversionSpecifier(conversionPosition, k)); + + if (k == ConversionSpecifier::InvalidSpecifier) { + H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg); + return false; // Keep processing format specifiers. + } + return FormatSpecifierResult(Start, FS); +} + +bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H, + const char *I, const char *E) { + // Keep looking for a format specifier until we have exhausted the string. + while (I != E) { + const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E); + // Did a fail-stop error of any kind occur when parsing the specifier? + // If so, don't do any more processing. + if (FSR.shouldStop()) + return true;; + // Did we exhaust the string or encounter an error that + // we can recover from? + if (!FSR.hasValue()) + continue; + // We have a format specifier. Pass it to the callback. + if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(), + I - FSR.getStart())) + return true; + } + assert(I == E && "Format string not exhausted"); + return false; +} + +FormatStringHandler::~FormatStringHandler() {} + +//===----------------------------------------------------------------------===// +// Methods on ArgTypeResult. +//===----------------------------------------------------------------------===// + +bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { + assert(isValid()); + + if (K == UnknownTy) + return true; + + if (K == SpecificTy) { + argTy = C.getCanonicalType(argTy).getUnqualifiedType(); + + if (T == argTy) + return true; + + if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) + switch (BT->getKind()) { + default: + break; + case BuiltinType::Char_S: + case BuiltinType::SChar: + return T == C.UnsignedCharTy; + case BuiltinType::Char_U: + case BuiltinType::UChar: + return T == C.SignedCharTy; + case BuiltinType::Short: + return T == C.UnsignedShortTy; + case BuiltinType::UShort: + return T == C.ShortTy; + case BuiltinType::Int: + return T == C.UnsignedIntTy; + case BuiltinType::UInt: + return T == C.IntTy; + case BuiltinType::Long: + return T == C.UnsignedLongTy; + case BuiltinType::ULong: + return T == C.LongTy; + case BuiltinType::LongLong: + return T == C.UnsignedLongLongTy; + case BuiltinType::ULongLong: + return T == C.LongLongTy; + } + + return false; + } + + if (K == CStrTy) { + const PointerType *PT = argTy->getAs<PointerType>(); + if (!PT) + return false; + + QualType pointeeTy = PT->getPointeeType(); + + if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>()) + switch (BT->getKind()) { + case BuiltinType::Void: + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::Char_S: + case BuiltinType::SChar: + return true; + default: + break; + } + + return false; + } + + if (K == WCStrTy) { + const PointerType *PT = argTy->getAs<PointerType>(); + if (!PT) + return false; + + QualType pointeeTy = PT->getPointeeType(); + return pointeeTy == C.WCharTy; + } + + return false; +} + +QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { + assert(isValid()); + if (K == SpecificTy) + return T; + if (K == CStrTy) + return C.getPointerType(C.CharTy); + if (K == WCStrTy) + return C.getPointerType(C.WCharTy); + if (K == ObjCPointerTy) + return C.ObjCBuiltinIdTy; + + return QualType(); +} + +//===----------------------------------------------------------------------===// +// Methods on OptionalAmount. +//===----------------------------------------------------------------------===// + +ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const { + return Ctx.IntTy; +} + +//===----------------------------------------------------------------------===// +// Methods on FormatSpecifier. +//===----------------------------------------------------------------------===// + +ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const { + if (!CS.consumesDataArgument()) + return ArgTypeResult::Invalid(); + + if (CS.isIntArg()) + switch (LM) { + case AsLongDouble: + return ArgTypeResult::Invalid(); + case None: return Ctx.IntTy; + case AsChar: return Ctx.SignedCharTy; + case AsShort: return Ctx.ShortTy; + case AsLong: return Ctx.LongTy; + case AsLongLong: return Ctx.LongLongTy; + case AsIntMax: + // FIXME: Return unknown for now. + return ArgTypeResult(); + case AsSizeT: return Ctx.getSizeType(); + case AsPtrDiff: return Ctx.getPointerDiffType(); + } + + if (CS.isUIntArg()) + switch (LM) { + case AsLongDouble: + return ArgTypeResult::Invalid(); + case None: return Ctx.UnsignedIntTy; + case AsChar: return Ctx.UnsignedCharTy; + case AsShort: return Ctx.UnsignedShortTy; + case AsLong: return Ctx.UnsignedLongTy; + case AsLongLong: return Ctx.UnsignedLongLongTy; + case AsIntMax: + // FIXME: Return unknown for now. + return ArgTypeResult(); + case AsSizeT: + // FIXME: How to get the corresponding unsigned + // version of size_t? + return ArgTypeResult(); + case AsPtrDiff: + // FIXME: How to get the corresponding unsigned + // version of ptrdiff_t? + return ArgTypeResult(); + } + + if (CS.isDoubleArg()) { + if (LM == AsLongDouble) + return Ctx.LongDoubleTy; + return Ctx.DoubleTy; + } + + if (CS.getKind() == ConversionSpecifier::CStrArg) + return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy + : ArgTypeResult::CStrTy); + + // FIXME: Handle other cases. + return ArgTypeResult(); +} + diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp deleted file mode 100644 index 4d7e8ade98f7..000000000000 --- a/lib/Analysis/ReturnStackAddressChecker.cpp +++ /dev/null @@ -1,114 +0,0 @@ -//== ReturnStackAddressChecker.cpp ------------------------------*- 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 ReturnStackAddressChecker, which is a path-sensitive -// check which looks for the addresses of stack variables being returned to -// callers. -// -//===----------------------------------------------------------------------===// - -#include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/ADT/SmallString.h" - -using namespace clang; - -namespace { -class ReturnStackAddressChecker : - public CheckerVisitor<ReturnStackAddressChecker> { - BuiltinBug *BT; -public: - ReturnStackAddressChecker() : BT(0) {} - static void *getTag(); - void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS); -}; -} - -void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) { - Eng.registerCheck(new ReturnStackAddressChecker()); -} - -void *ReturnStackAddressChecker::getTag() { - static int x = 0; return &x; -} - -void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, - const ReturnStmt *RS) { - - const Expr *RetE = RS->getRetValue(); - if (!RetE) - return; - - SVal V = C.getState()->getSVal(RetE); - const MemRegion *R = V.getAsRegion(); - - if (!R || !R->hasStackStorage()) - return; - - ExplodedNode *N = C.GenerateSink(); - - if (!N) - return; - - if (!BT) - BT = new BuiltinBug("Return of address to stack-allocated memory"); - - // Generate a report for this bug. - llvm::SmallString<100> buf; - llvm::raw_svector_ostream os(buf); - SourceRange range; - - // Get the base region, stripping away fields and elements. - R = R->getBaseRegion(); - - // Check if the region is a compound literal. - if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { - const CompoundLiteralExpr* CL = CR->getLiteralExpr(); - os << "Address of stack memory associated with a compound literal " - "declared on line " - << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart()) - << " returned to caller"; - range = CL->getSourceRange(); - } - else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) { - const Expr* ARE = AR->getExpr(); - SourceLocation L = ARE->getLocStart(); - range = ARE->getSourceRange(); - os << "Address of stack memory allocated by call to alloca() on line " - << C.getSourceManager().getInstantiationLineNumber(L) - << " returned to caller"; - } - else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { - const BlockDecl *BD = BR->getCodeRegion()->getDecl(); - SourceLocation L = BD->getLocStart(); - range = BD->getSourceRange(); - os << "Address of stack-allocated block declared on line " - << C.getSourceManager().getInstantiationLineNumber(L) - << " returned to caller"; - } - else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - os << "Address of stack memory associated with local variable '" - << VR->getString() << "' returned"; - range = VR->getDecl()->getSourceRange(); - } - else { - assert(false && "Invalid region in ReturnStackAddressChecker."); - return; - } - - RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); - report->addRange(RetE->getSourceRange()); - if (range.isValid()) - report->addRange(range); - - C.EmitReport(report); -} diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 6fa4b539dc40..bdc0e7c621f7 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -13,7 +13,6 @@ #include "clang/Analysis/Analyses/UninitializedValues.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" -#include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/AnalysisDiagnostic.h" #include "clang/AST/ASTContext.h" #include "clang/Analysis/FlowSensitive/DataflowSolver.h" diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index abbf6f9b6e41..094f7760a8ec 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -21,8 +21,10 @@ #include "clang/Analysis/AnalysisDiagnostic.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" @@ -385,6 +387,123 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { return Result; } +static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, + unsigned &Value) { + if (Memory + sizeof(unsigned) > MemoryEnd) + return true; + + memmove(&Value, Memory, sizeof(unsigned)); + Memory += sizeof(unsigned); + return false; +} + +static bool ReadSourceLocation(FileManager &FM, SourceManager &SM, + const char *&Memory, const char *MemoryEnd, + SourceLocation &Location) { + // Read the filename. + unsigned FileNameLen = 0; + if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) || + Memory + FileNameLen > MemoryEnd) + return true; + + llvm::StringRef FileName(Memory, FileNameLen); + Memory += FileNameLen; + + // Read the line, column. + unsigned Line = 0, Column = 0; + if (ReadUnsigned(Memory, MemoryEnd, Line) || + ReadUnsigned(Memory, MemoryEnd, Column)) + return true; + + if (FileName.empty()) { + Location = SourceLocation(); + return false; + } + + const FileEntry *File = FM.getFile(FileName); + if (!File) + return true; + + // Make sure that this file has an entry in the source manager. + if (!SM.hasFileInfo(File)) + SM.createFileID(File, SourceLocation(), SrcMgr::C_User); + + Location = SM.getLocation(File, Line, Column); + return false; +} + +DiagnosticBuilder Diagnostic::Deserialize(FileManager &FM, SourceManager &SM, + const char *&Memory, + const char *MemoryEnd) { + if (Memory == MemoryEnd) + return DiagnosticBuilder(0); + + // Read the severity level. + unsigned Level = 0; + if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Fatal) + return DiagnosticBuilder(0); + + // Read the source location. + SourceLocation Location; + if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location)) + return DiagnosticBuilder(0); + + // Read the diagnostic text. + if (Memory == MemoryEnd) + return DiagnosticBuilder(0); + + unsigned MessageLen = 0; + if (ReadUnsigned(Memory, MemoryEnd, MessageLen) || + Memory + MessageLen > MemoryEnd) + return DiagnosticBuilder(0); + + llvm::StringRef Message(Memory, MessageLen); + Memory += MessageLen; + + // At this point, we have enough information to form a diagnostic. Do so. + unsigned DiagID = getCustomDiagID((enum Level)Level, Message); + DiagnosticBuilder DB = Report(FullSourceLoc(Location, SM), DiagID); + if (Memory == MemoryEnd) + return DB; + + // Read the source ranges. + unsigned NumSourceRanges = 0; + if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges)) + return DB; + for (unsigned I = 0; I != NumSourceRanges; ++I) { + SourceLocation Begin, End; + if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) || + ReadSourceLocation(FM, SM, Memory, MemoryEnd, End)) + return DB; + + DB << SourceRange(Begin, End); + } + + // Read the fix-it hints. + unsigned NumFixIts = 0; + if (ReadUnsigned(Memory, MemoryEnd, NumFixIts)) + return DB; + for (unsigned I = 0; I != NumFixIts; ++I) { + SourceLocation RemoveBegin, RemoveEnd, InsertionLoc; + unsigned InsertLen = 0; + if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) || + ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) || + ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) || + ReadUnsigned(Memory, MemoryEnd, InsertLen) || + Memory + InsertLen > MemoryEnd) + return DB; + + CodeModificationHint Hint; + Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd); + Hint.InsertionLoc = InsertionLoc; + Hint.CodeToInsert.assign(Memory, Memory + InsertLen); + Memory += InsertLen; + DB << Hint; + } + + return DB; +} + struct WarningOption { const char *Name; const short *Members; @@ -510,7 +629,7 @@ bool Diagnostic::ProcessDiag() { // it. if (SuppressSystemWarnings && !ShouldEmitInSystemHeader && Info.getLocation().isValid() && - Info.getLocation().getSpellingLoc().isInSystemHeader() && + Info.getLocation().getInstantiationLoc().isInSystemHeader() && (DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) { LastDiagLevel = Diagnostic::Ignored; return false; @@ -917,6 +1036,104 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, } } +static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) { + OS.write((const char *)&Value, sizeof(unsigned)); +} + +static void WriteString(llvm::raw_ostream &OS, llvm::StringRef String) { + WriteUnsigned(OS, String.size()); + OS.write(String.data(), String.size()); +} + +static void WriteSourceLocation(llvm::raw_ostream &OS, + SourceManager *SM, + SourceLocation Location) { + if (!SM || Location.isInvalid()) { + // If we don't have a source manager or this location is invalid, + // just write an invalid location. + WriteUnsigned(OS, 0); + WriteUnsigned(OS, 0); + WriteUnsigned(OS, 0); + return; + } + + Location = SM->getInstantiationLoc(Location); + std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location); + + WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName()); + WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second)); + WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second)); +} + +void DiagnosticInfo::Serialize(Diagnostic::Level DiagLevel, + llvm::raw_ostream &OS) const { + SourceManager *SM = 0; + if (getLocation().isValid()) + SM = &const_cast<SourceManager &>(getLocation().getManager()); + + // Write the diagnostic level and location. + WriteUnsigned(OS, (unsigned)DiagLevel); + WriteSourceLocation(OS, SM, getLocation()); + + // Write the diagnostic message. + llvm::SmallString<64> Message; + FormatDiagnostic(Message); + WriteString(OS, Message); + + // Count the number of ranges that don't point into macros, since + // only simple file ranges serialize well. + unsigned NumNonMacroRanges = 0; + for (unsigned I = 0, N = getNumRanges(); I != N; ++I) { + SourceRange R = getRange(I); + if (R.getBegin().isMacroID() || R.getEnd().isMacroID()) + continue; + + ++NumNonMacroRanges; + } + + // Write the ranges. + WriteUnsigned(OS, NumNonMacroRanges); + if (NumNonMacroRanges) { + for (unsigned I = 0, N = getNumRanges(); I != N; ++I) { + SourceRange R = getRange(I); + if (R.getBegin().isMacroID() || R.getEnd().isMacroID()) + continue; + + WriteSourceLocation(OS, SM, R.getBegin()); + WriteSourceLocation(OS, SM, R.getEnd()); + } + } + + // Determine if all of the fix-its involve rewrites with simple file + // locations (not in macro instantiations). If so, we can write + // fix-it information. + unsigned NumFixIts = getNumCodeModificationHints(); + for (unsigned I = 0; I != NumFixIts; ++I) { + const CodeModificationHint &Hint = getCodeModificationHint(I); + if (Hint.RemoveRange.isValid() && + (Hint.RemoveRange.getBegin().isMacroID() || + Hint.RemoveRange.getEnd().isMacroID())) { + NumFixIts = 0; + break; + } + + if (Hint.InsertionLoc.isValid() && Hint.InsertionLoc.isMacroID()) { + NumFixIts = 0; + break; + } + } + + // Write the fix-its. + WriteUnsigned(OS, NumFixIts); + for (unsigned I = 0; I != NumFixIts; ++I) { + const CodeModificationHint &Hint = getCodeModificationHint(I); + WriteSourceLocation(OS, SM, Hint.RemoveRange.getBegin()); + WriteSourceLocation(OS, SM, Hint.RemoveRange.getEnd()); + WriteSourceLocation(OS, SM, Hint.InsertionLoc); + WriteString(OS, Hint.CodeToInsert); + } +} + /// IncludeInDiagnosticCounts - This method (whose default implementation /// returns true) indicates whether the diagnostics handled by this /// DiagnosticClient should be included in the number of diagnostics diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 401e6cba0692..16a61b7156fa 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -68,7 +68,8 @@ namespace { KEYCXX0X = 8, KEYGNU = 16, KEYMS = 32, - BOOLSUPPORT = 64 + BOOLSUPPORT = 64, + KEYALTIVEC = 128 }; } @@ -91,6 +92,7 @@ static void AddKeyword(const char *Keyword, unsigned KWLen, else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1; else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1; else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2; + else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; // Don't add this keyword if disabled in this language. if (AddResult == 0) return; diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile index f7335789384f..58ac7eb86e75 100644 --- a/lib/Basic/Makefile +++ b/lib/Basic/Makefile @@ -14,7 +14,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangBasic BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include ifdef CLANG_VENDOR diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 354bf7befbb3..b91671ad17b1 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -560,10 +560,14 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { SourceLocation SourceManager:: getInstantiationLocSlowCase(SourceLocation Loc) const { do { - std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); - Loc = getSLocEntry(LocInfo.first).getInstantiation() + // Note: If Loc indicates an offset into a token that came from a macro + // expansion (e.g. the 5th character of the token) we do not want to add + // this offset when going to the instantiation location. The instatiation + // location is the macro invocation, which the offset has nothing to do + // with. This is unlike when we get the spelling loc, because the offset + // directly correspond to the token whose spelling we're inspecting. + Loc = getSLocEntry(getFileID(Loc)).getInstantiation() .getInstantiationLocStart(); - Loc = Loc.getFileLocWithOffset(LocInfo.second); } while (!Loc.isFileID()); return Loc; diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 493beeea6dc5..136089fe90c2 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -150,39 +150,41 @@ void TargetInfo::setForcedLangOptions(LangOptions &Opts) { //===----------------------------------------------------------------------===// -static void removeGCCRegisterPrefix(const char *&Name) { +static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) { if (Name[0] == '%' || Name[0] == '#') - Name++; + Name = Name.substr(1); + + return Name; } /// isValidGCCRegisterName - Returns whether the passed in string /// is a valid register name according to GCC. This is used by Sema for /// inline asm statements. -bool TargetInfo::isValidGCCRegisterName(const char *Name) const { +bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const { + if (Name.empty()) + return false; + const char * const *Names; unsigned NumNames; // Get rid of any register prefix. - removeGCCRegisterPrefix(Name); + Name = removeGCCRegisterPrefix(Name); - - if (strcmp(Name, "memory") == 0 || - strcmp(Name, "cc") == 0) + if (Name == "memory" || Name == "cc") return true; getGCCRegNames(Names, NumNames); // If we have a number it maps to an entry in the register name array. if (isdigit(Name[0])) { - char *End; - int n = (int)strtol(Name, &End, 0); - if (*End == 0) + int n; + if (!Name.getAsInteger(0, n)) return n >= 0 && (unsigned)n < NumNames; } // Check register names. for (unsigned i = 0; i < NumNames; i++) { - if (strcmp(Name, Names[i]) == 0) + if (Name == Names[i]) return true; } @@ -195,7 +197,7 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const { for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { if (!Aliases[i].Aliases[j]) break; - if (strcmp(Aliases[i].Aliases[j], Name) == 0) + if (Aliases[i].Aliases[j] == Name) return true; } } @@ -203,10 +205,12 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const { return false; } -const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { +llvm::StringRef +TargetInfo::getNormalizedGCCRegisterName(llvm::StringRef Name) const { assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); - removeGCCRegisterPrefix(Name); + // Get rid of any register prefix. + Name = removeGCCRegisterPrefix(Name); const char * const *Names; unsigned NumNames; @@ -215,9 +219,8 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { // First, check if we have a number. if (isdigit(Name[0])) { - char *End; - int n = (int)strtol(Name, &End, 0); - if (*End == 0) { + int n; + if (!Name.getAsInteger(0, n)) { assert(n >= 0 && (unsigned)n < NumNames && "Out of bounds register number!"); return Names[n]; @@ -233,7 +236,7 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { if (!Aliases[i].Aliases[j]) break; - if (strcmp(Aliases[i].Aliases[j], Name) == 0) + if (Aliases[i].Aliases[j] == Name) return Aliases[i].Register; } } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index ea076ae0bbfc..c1cd96e361ed 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -74,7 +74,8 @@ public: } // end anonymous namespace -static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) { +static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, + const llvm::Triple &Triple) { Builder.defineMacro("__APPLE_CC__", "5621"); Builder.defineMacro("__APPLE__"); Builder.defineMacro("__MACH__"); @@ -96,51 +97,45 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) { if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); -} - -static void getDarwinOSXDefines(MacroBuilder &Builder, - const llvm::Triple &Triple) { - if (Triple.getOS() != llvm::Triple::Darwin) - return; - - // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5. - unsigned Maj, Min, Rev; - Triple.getDarwinNumber(Maj, Min, Rev); - - char MacOSXStr[] = "1000"; - if (Maj >= 4 && Maj <= 13) { // 10.0-10.9 - // darwin7 -> 1030, darwin8 -> 1040, darwin9 -> 1050, etc. - MacOSXStr[2] = '0' + Maj-4; - } - - // Handle minor version: 10.4.9 -> darwin8.9 -> "1049" - // Cap 10.4.11 -> darwin8.11 -> "1049" - MacOSXStr[3] = std::min(Min, 9U)+'0'; - Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", - MacOSXStr); -} - -static void getDarwinIPhoneOSDefines(MacroBuilder &Builder, - const llvm::Triple &Triple) { - if (Triple.getOS() != llvm::Triple::Darwin) - return; - // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5. + // Get the OS version number from the triple. unsigned Maj, Min, Rev; - Triple.getDarwinNumber(Maj, Min, Rev); - // When targetting iPhone OS, interpret the minor version and - // revision as the iPhone OS version - char iPhoneOSStr[] = "10000"; - if (Min >= 2 && Min <= 9) { // iPhone OS 2.0-9.0 - // darwin9.2.0 -> 20000, darwin9.3.0 -> 30000, etc. - iPhoneOSStr[0] = '0' + Min; + // If no version was given, default to to 10.4.0, for simplifying tests. + if (Triple.getOSName() == "darwin") { + Min = Rev = 0; + Maj = 8; + } else + Triple.getDarwinNumber(Maj, Min, Rev); + + // Set the appropriate OS version define. + if (Triple.getEnvironmentName() == "iphoneos") { + assert(Maj < 10 && Min < 99 && Rev < 99 && "Invalid version!"); + char Str[6]; + Str[0] = '0' + Maj; + Str[1] = '0' + (Min / 10); + Str[2] = '0' + (Min % 10); + Str[3] = '0' + (Rev / 10); + Str[4] = '0' + (Rev % 10); + Str[5] = '\0'; + Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str); + } else { + // For historical reasons that make little sense, the version passed here is + // the "darwin" version, which drops the 10 and offsets by 4. + Rev = Min; + Min = Maj - 4; + Maj = 10; + + assert(Triple.getEnvironmentName().empty() && "Invalid environment!"); + assert(Maj < 99 && Min < 10 && Rev < 10 && "Invalid version!"); + char Str[5]; + Str[0] = '0' + (Maj / 10); + Str[1] = '0' + (Maj % 10); + Str[2] = '0' + Min; + Str[3] = '0' + Rev; + Str[4] = '\0'; + Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); } - - // Handle minor version: 2.2 -> darwin9.2.2 -> 20200 - iPhoneOSStr[2] = std::min(Rev, 9U)+'0'; - Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", - iPhoneOSStr); } namespace { @@ -149,8 +144,7 @@ class DarwinTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { - getDarwinDefines(Builder, Opts); - getDarwinOSXDefines(Builder, Triple); + getDarwinDefines(Builder, Opts, Triple); } public: @@ -159,11 +153,7 @@ public: this->TLSSupported = false; } - virtual const char *getUnicodeStringSection() const { - return "__TEXT,__ustring"; - } - - virtual std::string isValidSectionSpecifier(const llvm::StringRef &SR) const { + virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const { // Let MCSectionMachO validate this. llvm::StringRef Segment, Section; unsigned TAA, StubSize; @@ -201,16 +191,10 @@ protected: // FreeBSD defines; list based off of gcc output // FIXME: Move version number handling to llvm::Triple. - const char *FreeBSD = strstr(Triple.getTriple().c_str(), - "-freebsd"); - FreeBSD += strlen("-freebsd"); - char release[] = "X"; - release[0] = FreeBSD[0]; - char version[] = "X00001"; - version[0] = FreeBSD[0]; - - Builder.defineMacro("__FreeBSD__", release); - Builder.defineMacro("__FreeBSD_cc_version", version); + llvm::StringRef Release = Triple.getOSName().substr(strlen("freebsd"), 1); + + Builder.defineMacro("__FreeBSD__", Release); + Builder.defineMacro("__FreeBSD_cc_version", Release + "00001"); Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); @@ -643,9 +627,13 @@ class X86TargetInfo : public TargetInfo { enum X86SSEEnum { NoMMXSSE, MMX, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42 } SSELevel; + enum AMD3DNowEnum { + NoAMD3DNow, AMD3DNow, AMD3DNowAthlon + } AMD3DNowLevel; + public: X86TargetInfo(const std::string& triple) - : TargetInfo(triple), SSELevel(NoMMXSSE) { + : TargetInfo(triple), SSELevel(NoMMXSSE), AMD3DNowLevel(NoAMD3DNow) { LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } virtual void getTargetBuiltins(const Builtin::Info *&Records, @@ -810,6 +798,14 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { .Case("mmx", MMX) .Default(NoMMXSSE); SSELevel = std::max(SSELevel, Level); + + AMD3DNowEnum ThreeDNowLevel = + llvm::StringSwitch<AMD3DNowEnum>(Features[i].substr(1)) + .Case("3dnowa", AMD3DNowAthlon) + .Case("3dnow", AMD3DNow) + .Default(NoAMD3DNow); + + AMD3DNowLevel = std::max(AMD3DNowLevel, ThreeDNowLevel); } } @@ -864,6 +860,16 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case NoMMXSSE: break; } + + // Each case falls through to the previous one here. + switch (AMD3DNowLevel) { + case AMD3DNowAthlon: + Builder.defineMacro("__3dNOW_A__"); + case AMD3DNow: + Builder.defineMacro("__3dNOW__"); + case NoAMD3DNow: + break; + } } @@ -1224,7 +1230,7 @@ public: // FIXME: We need support for -meabi... we could just mangle it into the // name. if (Name == "apcs-gnu") { - DoubleAlign = LongLongAlign = 32; + DoubleAlign = LongLongAlign = LongDoubleAlign = 32; SizeType = UnsignedLong; if (IsThumb) { @@ -1379,9 +1385,6 @@ public: // when Neon instructions are actually available. if (FPU == NeonFPU && !SoftFloat && IsThumb2) Builder.defineMacro("__ARM_NEON__"); - - if (getTriple().getOS() == llvm::Triple::Darwin) - Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { @@ -1461,8 +1464,7 @@ class DarwinARMTargetInfo : protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { - getDarwinDefines(Builder, Opts); - getDarwinIPhoneOSDefines(Builder, Triple); + getDarwinDefines(Builder, Opts, Triple); } public: @@ -1617,23 +1619,25 @@ namespace { virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { Builder.defineMacro("__pic16"); + Builder.defineMacro("__PIC16"); Builder.defineMacro("rom", "__attribute__((address_space(1)))"); Builder.defineMacro("ram", "__attribute__((address_space(0)))"); - Builder.defineMacro("_section(SectName)", + Builder.defineMacro("__section(SectName)", "__attribute__((section(SectName)))"); Builder.defineMacro("near", "__attribute__((section(\"Address=NEAR\")))"); - Builder.defineMacro("_address(Addr)", + Builder.defineMacro("__address(Addr)", "__attribute__((section(\"Address=\"#Addr)))"); - Builder.defineMacro("_CONFIG(conf)", "asm(\"CONFIG \"#conf)"); - Builder.defineMacro("_interrupt", + Builder.defineMacro("__config(conf)", "asm(\"CONFIG \"#conf)"); + Builder.defineMacro("__idlocs(value)", "asm(\"__IDLOCS \"#value)"); + Builder.defineMacro("interrupt", "__attribute__((section(\"interrupt=0x4\"))) \ __attribute__((used))"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const {} virtual const char *getVAListDeclaration() const { - return ""; + return "typedef char* __builtin_va_list;"; } virtual const char *getClobbers() const { return ""; @@ -1656,13 +1660,10 @@ namespace { public: MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) { TLSSupported = false; - IntWidth = 16; - LongWidth = 32; - LongLongWidth = 64; - PointerWidth = 16; - IntAlign = 8; - LongAlign = LongLongAlign = 8; - PointerAlign = 8; + IntWidth = 16; IntAlign = 16; + LongWidth = 32; LongLongWidth = 64; + LongAlign = LongLongAlign = 16; + PointerWidth = 16; PointerAlign = 16; SizeType = UnsignedInt; IntMaxType = SignedLong; UIntMaxType = UnsignedLong; diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index b1b250f82933..98cf42b8c3d9 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -21,67 +21,55 @@ using namespace std; namespace clang { llvm::StringRef getClangRepositoryPath() { - static const char *Path = 0; - if (Path) - return Path; - - static char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"; - char *End = strstr(URL, "/lib/Basic"); + static const char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"; + const char *URLEnd = URL + strlen(URL); + + const char *End = strstr(URL, "/lib/Basic"); if (End) - *End = 0; - + URLEnd = End; + End = strstr(URL, "/clang/tools/clang"); if (End) - *End = 0; - - char *Begin = strstr(URL, "cfe/"); - if (Begin) { - Path = Begin + 4; - return Path; - } - - Path = URL; - return Path; -} + URLEnd = End; + + const char *Begin = strstr(URL, "cfe/"); + if (Begin) + return llvm::StringRef(Begin + 4, URLEnd - Begin - 4); + return llvm::StringRef(URL, URLEnd - URL); +} -llvm::StringRef getClangRevision() { +std::string getClangRevision() { #ifndef SVN_REVISION // Subversion was not available at build time? - return llvm::StringRef(); + return ""; #else - static std::string revision; - if (revision.empty()) { - llvm::raw_string_ostream OS(revision); - OS << strtol(SVN_REVISION, 0, 10); - } + std::string revision; + llvm::raw_string_ostream OS(revision); + OS << strtol(SVN_REVISION, 0, 10); return revision; #endif } -llvm::StringRef getClangFullRepositoryVersion() { - static std::string buf; - if (buf.empty()) { - llvm::raw_string_ostream OS(buf); - OS << getClangRepositoryPath(); - llvm::StringRef Revision = getClangRevision(); - if (!Revision.empty()) - OS << ' ' << Revision; - } +std::string getClangFullRepositoryVersion() { + std::string buf; + llvm::raw_string_ostream OS(buf); + OS << getClangRepositoryPath(); + const std::string &Revision = getClangRevision(); + if (!Revision.empty()) + OS << ' ' << Revision; return buf; } -const char *getClangFullVersion() { - static std::string buf; - if (buf.empty()) { - llvm::raw_string_ostream OS(buf); +std::string getClangFullVersion() { + std::string buf; + llvm::raw_string_ostream OS(buf); #ifdef CLANG_VENDOR - OS << CLANG_VENDOR; + OS << CLANG_VENDOR; #endif - OS << "clang version " CLANG_VERSION_STRING " (" - << getClangFullRepositoryVersion() << ')'; - } - return buf.c_str(); + OS << "clang version " CLANG_VERSION_STRING " (" + << getClangFullRepositoryVersion() << ')'; + return buf; } - + } // end namespace clang diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 2bfaa445e568..bc2cd460d92b 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -10,3 +10,4 @@ add_subdirectory(Rewrite) add_subdirectory(Driver) add_subdirectory(Frontend) add_subdirectory(Index) +add_subdirectory(Checker) diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp new file mode 100644 index 000000000000..e95a86b838b6 --- /dev/null +++ b/lib/Checker/AdjustedReturnValueChecker.cpp @@ -0,0 +1,98 @@ +//== AdjustedReturnValueChecker.cpp -----------------------------*- 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 AdjustedReturnValueChecker, a simple check to see if the +// return value of a function call is different than the one the caller thinks +// it is. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.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" + +using namespace clang; + +namespace { +class AdjustedReturnValueChecker : + public CheckerVisitor<AdjustedReturnValueChecker> { +public: + AdjustedReturnValueChecker() {} + + void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); + + static void *getTag() { + static int x = 0; return &x; + } +}; +} + +void clang::RegisterAdjustedReturnValueChecker(GRExprEngine &Eng) { + Eng.registerCheck(new AdjustedReturnValueChecker()); +} + +void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C, + const CallExpr *CE) { + + // Get the result type of the call. + QualType expectedResultTy = CE->getType(); + + // Fetch the signature of the called function. + const GRState *state = C.getState(); + + SVal V = state->getSVal(CE); + + if (V.isUnknown()) + return; + + // Casting to void? Discard the value. + if (expectedResultTy->isVoidType()) { + C.GenerateNode(state->BindExpr(CE, UnknownVal())); + return; + } + + const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion(); + if (!callee) + return; + + QualType actualResultTy; + + if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) { + const FunctionDecl *FD = FT->getDecl(); + actualResultTy = FD->getResultType(); + } + else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) { + const BlockTextRegion *BR = BD->getCodeRegion(); + const BlockPointerType *BT = + BR->getLocationType(C.getASTContext())->getAs<BlockPointerType>(); + const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>(); + actualResultTy = FT->getResultType(); + } + + // Can this happen? + if (actualResultTy.isNull()) + return; + + // For now, ignore references. + if (actualResultTy->getAs<ReferenceType>()) + return; + + + // Are they the same? + if (expectedResultTy != actualResultTy) { + // FIXME: Do more checking and actual emit an error. At least performing + // the cast avoids some assertion failures elsewhere. + SValuator &SVator = C.getSValuator(); + V = SVator.EvalCast(V, expectedResultTy, actualResultTy); + C.GenerateNode(state->BindExpr(CE, V)); + } +} diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Checker/ArrayBoundChecker.cpp index 49c86068265b..74fb06f45564 100644 --- a/lib/Analysis/ArrayBoundChecker.cpp +++ b/lib/Checker/ArrayBoundChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Checker/AttrNonNullChecker.cpp index aa21700c2483..83dc13e92b63 100644 --- a/lib/Analysis/AttrNonNullChecker.cpp +++ b/lib/Checker/AttrNonNullChecker.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/BugReporter/BugReporter.h" #include "GRExprEngineInternalChecks.h" using namespace clang; diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Checker/BasicConstraintManager.cpp index 6dfc470530a4..e89546ecb018 100644 --- a/lib/Analysis/BasicConstraintManager.cpp +++ b/lib/Checker/BasicConstraintManager.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "SimpleConstraintManager.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/GRStateTrait.h" -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/PathSensitive/GRTransferFuncs.h" #include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp index 67483d979291..d6c09a2e04a6 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Checker/BasicObjCFoundationChecks.cpp @@ -15,15 +15,15 @@ #include "BasicObjCFoundationChecks.h" -#include "clang/Analysis/PathSensitive/ExplodedGraph.h" -#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/MemRegion.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/LocalCheckers.h" +#include "clang/Checker/PathSensitive/ExplodedGraph.h" +#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/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" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" @@ -163,61 +163,22 @@ bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N, // FIXME: This is going to be really slow doing these checks with // lexical comparisons. - std::string name = S.getAsString(); - assert (!name.empty()); - const char* cstr = &name[0]; - unsigned len = name.size(); - - switch (len) { - default: - break; - case 8: - if (!strcmp(cstr, "compare:")) - return CheckNilArg(N, 0); - - break; - - case 15: - // FIXME: Checking for initWithFormat: will not work in most cases - // yet because [NSString alloc] returns id, not NSString*. We will - // need support for tracking expected-type information in the analyzer - // to find these errors. - if (!strcmp(cstr, "initWithFormat:")) - return CheckNilArg(N, 0); - - break; - - case 16: - if (!strcmp(cstr, "compare:options:")) - return CheckNilArg(N, 0); - - break; - - case 22: - if (!strcmp(cstr, "compare:options:range:")) - return CheckNilArg(N, 0); - - break; - - case 23: - - if (!strcmp(cstr, "caseInsensitiveCompare:")) - return CheckNilArg(N, 0); - - break; - - case 29: - if (!strcmp(cstr, "compare:options:range:locale:")) - return CheckNilArg(N, 0); - - break; - - case 37: - if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:")) - return CheckNilArg(N, 0); - - break; - } + std::string NameStr = S.getAsString(); + llvm::StringRef Name(NameStr); + assert(!Name.empty()); + + // FIXME: Checking for initWithFormat: will not work in most cases + // yet because [NSString alloc] returns id, not NSString*. We will + // need support for tracking expected-type information in the analyzer + // to find these errors. + if (Name == "caseInsensitiveCompare:" || + Name == "compare:" || + Name == "compare:options:" || + Name == "compare:options:range:" || + Name == "compare:options:range:locale:" || + Name == "componentsSeparatedByCharactersInSet:" || + Name == "initWithFormat:") + return CheckNilArg(N, 0); return false; } diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Checker/BasicObjCFoundationChecks.h index 679c6dc1df2d..679c6dc1df2d 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.h +++ b/lib/Checker/BasicObjCFoundationChecks.h diff --git a/lib/Analysis/BasicStore.cpp b/lib/Checker/BasicStore.cpp index 224281b17770..6ef29429f681 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Checker/BasicStore.cpp @@ -13,8 +13,8 @@ #include "clang/AST/ExprObjC.h" #include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Checker/PathSensitive/GRState.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; @@ -40,25 +40,19 @@ public: ~BasicStoreManager() {} - SubRegionMap *getSubRegionMap(const GRState *state) { + SubRegionMap *getSubRegionMap(Store store) { return new BasicStoreSubRegionMap(); } - SValuator::CastResult Retrieve(const GRState *state, Loc loc, - QualType T = QualType()); + SVal Retrieve(Store store, Loc loc, QualType T = QualType()); - const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, - const Expr *E, unsigned Count, - InvalidatedSymbols *IS); - - const GRState *Bind(const GRState *state, Loc L, SVal V) { - return state->makeWithStore(BindInternal(state->getStore(), L, V)); - } + Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E, + unsigned Count, InvalidatedSymbols *IS); Store scanForIvars(Stmt *B, const Decl* SelfDecl, const MemRegion *SelfRegion, Store St); - Store BindInternal(Store St, Loc loc, SVal V); + Store Bind(Store St, Loc loc, SVal V); Store Remove(Store St, Loc loc); Store getInitialStore(const LocationContext *InitLoc); @@ -67,38 +61,28 @@ public: return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC)); } - const GRState *BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr*, - const LocationContext*, - SVal val) { - return state; + Store BindCompoundLiteral(Store store, const CompoundLiteralExpr*, + const LocationContext*, SVal val) { + return store; } - SVal getLValueVar(const VarDecl *VD, const LocationContext *LC); - SVal getLValueString(const StringLiteral *S); - SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base); - SVal getLValueField(const FieldDecl *D, SVal Base); - SVal getLValueElement(QualType elementType, SVal Offset, SVal Base); - /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit /// conversions between arrays and pointers. SVal ArrayToPointer(Loc Array) { return Array; } /// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values. /// It updatees the GRState object in place with the values removed. - void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper, + Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); void iterBindings(Store store, BindingsHandler& f); - const GRState *BindDecl(const GRState *state, const VarRegion *VR, - SVal InitVal) { - return state->makeWithStore(BindDeclInternal(state->getStore(), VR, - &InitVal)); + Store BindDecl(Store store, const VarRegion *VR, SVal InitVal) { + return BindDeclInternal(store, VR, &InitVal); } - const GRState *BindDeclWithNoInit(const GRState *state, const VarRegion *VR) { - return state->makeWithStore(BindDeclInternal(state->getStore(), VR, 0)); + Store BindDeclWithNoInit(Store store, const VarRegion *VR) { + return BindDeclInternal(store, VR, 0); } Store BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal); @@ -121,114 +105,6 @@ StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) { return new BasicStoreManager(StMgr); } -SVal BasicStoreManager::getLValueVar(const VarDecl* VD, - const LocationContext *LC) { - return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC)); -} - -SVal BasicStoreManager::getLValueString(const StringLiteral* S) { - return ValMgr.makeLoc(MRMgr.getStringRegion(S)); -} - -SVal BasicStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) { - - if (Base.isUnknownOrUndef()) - return Base; - - Loc BaseL = cast<Loc>(Base); - - if (isa<loc::MemRegionVal>(BaseL)) { - const MemRegion *BaseR = cast<loc::MemRegionVal>(BaseL).getRegion(); - return ValMgr.makeLoc(MRMgr.getObjCIvarRegion(D, BaseR)); - } - - return UnknownVal(); -} - -SVal BasicStoreManager::getLValueField(const FieldDecl* D, SVal Base) { - - if (Base.isUnknownOrUndef()) - return Base; - - Loc BaseL = cast<Loc>(Base); - const MemRegion* BaseR = 0; - - switch(BaseL.getSubKind()) { - case loc::GotoLabelKind: - return UndefinedVal(); - - case loc::MemRegionKind: - BaseR = cast<loc::MemRegionVal>(BaseL).getRegion(); - break; - - case loc::ConcreteIntKind: - // While these seem funny, this can happen through casts. - // FIXME: What we should return is the field offset. For example, - // add the field offset to the integer value. That way funny things - // like this work properly: &(((struct foo *) 0xa)->f) - return Base; - - default: - assert ("Unhandled Base."); - return Base; - } - - return ValMgr.makeLoc(MRMgr.getFieldRegion(D, BaseR)); -} - -SVal BasicStoreManager::getLValueElement(QualType elementType, - SVal Offset, SVal Base) { - - if (Base.isUnknownOrUndef()) - return Base; - - Loc BaseL = cast<Loc>(Base); - const MemRegion* BaseR = 0; - - switch(BaseL.getSubKind()) { - case loc::GotoLabelKind: - // Technically we can get here if people do funny things with casts. - return UndefinedVal(); - - case loc::MemRegionKind: { - const MemRegion *R = cast<loc::MemRegionVal>(BaseL).getRegion(); - - if (isa<ElementRegion>(R)) { - // int x; - // char* y = (char*) &x; - // 'y' => ElementRegion(0, VarRegion('x')) - // y[0] = 'a'; - return Base; - } - - if (isa<TypedRegion>(R) || isa<SymbolicRegion>(R)) { - BaseR = R; - break; - } - - break; - } - - case loc::ConcreteIntKind: - // While these seem funny, this can happen through casts. - // FIXME: What we should return is the field offset. For example, - // add the field offset to the integer value. That way funny things - // like this work properly: &(((struct foo *) 0xa)->f) - return Base; - - default: - assert ("Unhandled Base."); - return Base; - } - - if (BaseR) { - return ValMgr.makeLoc(MRMgr.getElementRegion(elementType, UnknownVal(), - BaseR, getContext())); - } - else - return UnknownVal(); -} - static bool isHigherOrderRawPtr(QualType T, ASTContext &C) { bool foundPointer = false; while (1) { @@ -250,11 +126,9 @@ static bool isHigherOrderRawPtr(QualType T, ASTContext &C) { } } -SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state, - Loc loc, QualType T) { - +SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) { if (isa<UnknownVal>(loc)) - return SValuator::CastResult(state, UnknownVal()); + return UnknownVal(); assert(!isa<UndefinedVal>(loc)); @@ -264,33 +138,32 @@ SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state, const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion(); if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R))) - return SValuator::CastResult(state, UnknownVal()); + return UnknownVal(); - BindingsTy B = GetBindings(state->getStore()); + BindingsTy B = GetBindings(store); BindingsTy::data_type *Val = B.lookup(R); if (!Val) break; - return SValuator::CastResult(state, - CastRetrievedVal(*Val, cast<TypedRegion>(R), T)); + return CastRetrievedVal(*Val, cast<TypedRegion>(R), T); } case loc::ConcreteIntKind: // Some clients may call GetSVal with such an option simply because // they are doing a quick scan through their Locs (potentially to // invalidate their bindings). Just return Undefined. - return SValuator::CastResult(state, UndefinedVal()); + return UndefinedVal(); default: assert (false && "Invalid Loc."); break; } - return SValuator::CastResult(state, UnknownVal()); + return UnknownVal(); } -Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) { +Store BasicStoreManager::Bind(Store store, Loc loc, SVal V) { if (isa<loc::ConcreteInt>(loc)) return store; @@ -352,12 +225,10 @@ Store BasicStoreManager::Remove(Store store, Loc loc) { } } -void -BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, - SymbolReaper& SymReaper, +Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) { - Store store = state.getStore(); BindingsTy B = GetBindings(store); typedef SVal::symbol_iterator symbol_iterator; @@ -398,7 +269,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, break; Marked.insert(MR); - SVal X = Retrieve(&state, loc::MemRegionVal(MR)).getSVal(); + SVal X = Retrieve(store, loc::MemRegionVal(MR)); // FIXME: We need to handle symbols nested in region definitions. for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI) @@ -431,8 +302,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, } } - // Write the store back. - state.setStore(store); + return store; } Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, @@ -452,7 +322,7 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, const MemRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(), SelfRegion); SVal X = ValMgr.getRegionValueSymbolVal(IVR); - St = BindInternal(St, ValMgr.makeLoc(IVR), X); + St = Bind(St, ValMgr.makeLoc(IVR), X); } } } @@ -485,8 +355,7 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { const MemRegion *SelfRegion = ValMgr.getRegionValueSymbolVal(VR).getAsRegion(); assert(SelfRegion); - St = BindInternal(St, ValMgr.makeLoc(VR), - loc::MemRegionVal(SelfRegion)); + St = Bind(St, ValMgr.makeLoc(VR), loc::MemRegionVal(SelfRegion)); // Scan the method for ivar references. While this requires an // entire AST scan, the cost should not be high in practice. St = scanForIvars(MD->getBody(), PD, SelfRegion, St); @@ -505,7 +374,7 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { if (R->hasGlobalsOrParametersStorage()) X = ValMgr.getRegionValueSymbolVal(R); - St = BindInternal(St, ValMgr.makeLoc(R), X); + St = Bind(St, ValMgr.makeLoc(R), X); } } return St; @@ -543,16 +412,16 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, if (!InitVal) { QualType T = VD->getType(); if (Loc::IsLocType(T)) - store = BindInternal(store, loc::MemRegionVal(VR), + store = Bind(store, loc::MemRegionVal(VR), loc::ConcreteInt(BasicVals.getValue(0, T))); else if (T->isIntegerType()) - store = BindInternal(store, loc::MemRegionVal(VR), + store = Bind(store, loc::MemRegionVal(VR), nonloc::ConcreteInt(BasicVals.getValue(0, T))); else { // assert(0 && "ignore other types of variables"); } } else { - store = BindInternal(store, loc::MemRegionVal(VR), *InitVal); + store = Bind(store, loc::MemRegionVal(VR), *InitVal); } } } else { @@ -560,7 +429,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, QualType T = VD->getType(); if (ValMgr.getSymbolManager().canSymbolicate(T)) { SVal V = InitVal ? *InitVal : UndefinedVal(); - store = BindInternal(store, loc::MemRegionVal(VR), V); + store = Bind(store, loc::MemRegionVal(VR), V); } } @@ -600,18 +469,18 @@ StoreManager::BindingsHandler::~BindingsHandler() {} // Binding invalidation. //===----------------------------------------------------------------------===// -const GRState *BasicStoreManager::InvalidateRegion(const GRState *state, - const MemRegion *R, - const Expr *E, - unsigned Count, - InvalidatedSymbols *IS) { +Store BasicStoreManager::InvalidateRegion(Store store, + const MemRegion *R, + const Expr *E, + unsigned Count, + InvalidatedSymbols *IS) { R = R->StripCasts(); if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R))) - return state; + return store; if (IS) { - BindingsTy B = GetBindings(state->getStore()); + BindingsTy B = GetBindings(store); if (BindingsTy::data_type *Val = B.lookup(R)) { if (SymbolRef Sym = Val->getAsSymbol()) IS->insert(Sym); @@ -620,6 +489,6 @@ const GRState *BasicStoreManager::InvalidateRegion(const GRState *state, QualType T = cast<TypedRegion>(R)->getValueType(R->getContext()); SVal V = ValMgr.getConjuredSymbolVal(R, E, T, Count); - return Bind(state, loc::MemRegionVal(R), V); + return Bind(store, loc::MemRegionVal(R), V); } diff --git a/lib/Analysis/BasicValueFactory.cpp b/lib/Checker/BasicValueFactory.cpp index b33c277f86f9..246beead1208 100644 --- a/lib/Analysis/BasicValueFactory.cpp +++ b/lib/Checker/BasicValueFactory.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/BasicValueFactory.h" +#include "clang/Checker/PathSensitive/BasicValueFactory.h" using namespace clang; @@ -24,9 +24,8 @@ void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T, } void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID, - const GRState *state, - const TypedRegion *region) { - ID.AddPointer(state); + const void *store,const TypedRegion *region) { + ID.AddPointer(store); ID.AddPointer(region); } @@ -124,10 +123,10 @@ BasicValueFactory::getCompoundValData(QualType T, } const LazyCompoundValData* -BasicValueFactory::getLazyCompoundValData(const GRState *state, +BasicValueFactory::getLazyCompoundValData(const void *store, const TypedRegion *region) { llvm::FoldingSetNodeID ID; - LazyCompoundValData::Profile(ID, state, region); + LazyCompoundValData::Profile(ID, store, region); void* InsertPos; LazyCompoundValData *D = @@ -135,7 +134,7 @@ BasicValueFactory::getLazyCompoundValData(const GRState *state, if (!D) { D = (LazyCompoundValData*) BPAlloc.Allocate<LazyCompoundValData>(); - new (D) LazyCompoundValData(state, region); + new (D) LazyCompoundValData(store, region); LazyCompoundValDataSet.InsertNode(D, InsertPos); } diff --git a/lib/Analysis/BugReporter.cpp b/lib/Checker/BugReporter.cpp index 2a9531df60f1..0cf593b26009 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Checker/BugReporter.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/AST/ASTContext.h" #include "clang/Analysis/CFG.h" #include "clang/AST/Expr.h" @@ -21,7 +21,7 @@ #include "clang/AST/StmtObjC.h" #include "clang/Basic/SourceManager.h" #include "clang/Analysis/ProgramPoint.h" -#include "clang/Analysis/PathDiagnostic.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" diff --git a/lib/Analysis/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp index 87de30ae7aec..6cf41b14dc5a 100644 --- a/lib/Analysis/BugReporterVisitors.cpp +++ b/lib/Checker/BugReporterVisitors.cpp @@ -14,9 +14,9 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/PathSensitive/GRState.h" using namespace clang; @@ -323,7 +323,7 @@ void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC, if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V) || V.isUndef()) { - registerFindLastStore(BRC, R, V); + ::registerFindLastStore(BRC, R, V); } } } @@ -347,3 +347,21 @@ void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC, } } } + +void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC, + const void *data, + const ExplodedNode* N) { + + const MemRegion *R = static_cast<const MemRegion*>(data); + + if (!R) + return; + + const GRState *state = N->getState(); + SVal V = state->getSVal(R); + + if (V.isUnknown()) + return; + + BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); +} diff --git a/lib/Analysis/BuiltinFunctionChecker.cpp b/lib/Checker/BuiltinFunctionChecker.cpp index a89ad2164b30..8711492049c5 100644 --- a/lib/Analysis/BuiltinFunctionChecker.cpp +++ b/lib/Checker/BuiltinFunctionChecker.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Checker/PathSensitive/Checker.h" #include "clang/Basic/Builtins.h" #include "llvm/ADT/StringSwitch.h" diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp index 5a15fbfb1f05..324916a6f6eb 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Checker/CFRefCount.cpp @@ -14,15 +14,16 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" -#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" -#include "clang/Analysis/PathSensitive/GRStateTrait.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/SymbolManager.h" -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/Checkers/LocalCheckers.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/SymbolManager.h" +#include "clang/Checker/PathSensitive/GRTransferFuncs.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/DomainSpecific/CocoaConventions.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/StmtVisitor.h" #include "llvm/ADT/DenseMap.h" @@ -34,129 +35,8 @@ #include <stdarg.h> using namespace clang; - -//===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -// The "fundamental rule" for naming conventions of methods: -// (url broken into two lines) -// http://developer.apple.com/documentation/Cocoa/Conceptual/ -// MemoryMgmt/Tasks/MemoryManagementRules.html -// -// "You take ownership of an object if you create it using a method whose name -// begins with "alloc" or "new" or contains "copy" (for example, alloc, -// newObject, or mutableCopy), or if you send it a retain message. You are -// responsible for relinquishing ownership of objects you own using release -// or autorelease. Any other time you receive an object, you must -// not release it." -// - -using llvm::StrInStrNoCase; using llvm::StringRef; - -enum NamingConvention { NoConvention, CreateRule, InitRule }; - -static inline bool isWordEnd(char ch, char prev, char next) { - return ch == '\0' - || (islower(prev) && isupper(ch)) // xxxC - || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate - || !isalpha(ch); -} - -static inline const char* parseWord(const char* s) { - char ch = *s, prev = '\0'; - assert(ch != '\0'); - char next = *(s+1); - while (!isWordEnd(ch, prev, next)) { - prev = ch; - ch = next; - next = *((++s)+1); - } - return s; -} - -static NamingConvention deriveNamingConvention(Selector S) { - IdentifierInfo *II = S.getIdentifierInfoForSlot(0); - - if (!II) - return NoConvention; - - const char *s = II->getNameStart(); - - // A method/function name may contain a prefix. We don't know it is there, - // however, until we encounter the first '_'. - bool InPossiblePrefix = true; - bool AtBeginning = true; - NamingConvention C = NoConvention; - - while (*s != '\0') { - // Skip '_'. - if (*s == '_') { - if (InPossiblePrefix) { - // If we already have a convention, return it. Otherwise, skip - // the prefix as if it wasn't there. - if (C != NoConvention) - break; - - InPossiblePrefix = false; - AtBeginning = true; - assert(C == NoConvention); - } - ++s; - continue; - } - - // Skip numbers, ':', etc. - if (!isalpha(*s)) { - ++s; - continue; - } - - const char *wordEnd = parseWord(s); - assert(wordEnd > s); - unsigned len = wordEnd - s; - - switch (len) { - default: - break; - case 3: - // Methods starting with 'new' follow the create rule. - if (AtBeginning && StringRef(s, len).equals_lower("new")) - C = CreateRule; - break; - case 4: - // Methods starting with 'alloc' or contain 'copy' follow the - // create rule - if (C == NoConvention && StringRef(s, len).equals_lower("copy")) - C = CreateRule; - else // Methods starting with 'init' follow the init rule. - if (AtBeginning && StringRef(s, len).equals_lower("init")) - C = InitRule; - break; - case 5: - if (AtBeginning && StringRef(s, len).equals_lower("alloc")) - C = CreateRule; - break; - } - - // If we aren't in the prefix and have a derived convention then just - // return it now. - if (!InPossiblePrefix && C != NoConvention) - return C; - - AtBeginning = false; - s = wordEnd; - } - - // We will get here if there wasn't more than one word - // after the prefix. - return C; -} - -static bool followsFundamentalRule(Selector S) { - return deriveNamingConvention(S) == CreateRule; -} +using llvm::StrInStrNoCase; static const ObjCMethodDecl* ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { @@ -194,34 +74,6 @@ public: } // end anonymous namespace //===----------------------------------------------------------------------===// -// Type querying functions. -//===----------------------------------------------------------------------===// - -static bool isRefType(QualType RetTy, const char* prefix, - ASTContext* Ctx = 0, const char* name = 0) { - - // Recursively walk the typedef stack, allowing typedefs of reference types. - while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { - llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName(); - if (TDName.startswith(prefix) && TDName.endswith("Ref")) - return true; - - RetTy = TD->getDecl()->getUnderlyingType(); - } - - if (!Ctx || !name) - return false; - - // Is the type void*? - const PointerType* PT = RetTy->getAs<PointerType>(); - if (!(PT->getPointeeType().getUnqualifiedType() == Ctx->VoidTy)) - return false; - - // Does the name start with the prefix? - return llvm::StringRef(name).startswith(prefix); -} - -//===----------------------------------------------------------------------===// // Primitives used for constructing summaries for function/method calls. //===----------------------------------------------------------------------===// @@ -853,7 +705,7 @@ public: RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD); RetainSummary* getCFSummaryGetRule(FunctionDecl* FD); - RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName); + RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, StringRef FName); RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff, ArgEffect ReceiverEff = DoNothing, @@ -880,10 +732,6 @@ public: void InitializeClassMethodSummaries(); void InitializeMethodSummaries(); - - bool isTrackedObjCObjectType(QualType T); - bool isTrackedCFObjectType(QualType T); - private: void addClsMethSummary(IdentifierInfo* ClsII, Selector S, @@ -1072,62 +920,15 @@ RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff, } //===----------------------------------------------------------------------===// -// Predicates. -//===----------------------------------------------------------------------===// - -bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) { - if (!Ty->isObjCObjectPointerType()) - return false; - - const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>(); - - // Can be true for objects with the 'NSObject' attribute. - if (!PT) - return true; - - // We assume that id<..>, id, and "Class" all represent tracked objects. - if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || - PT->isObjCClassType()) - return true; - - // Does the interface subclass NSObject? - // FIXME: We can memoize here if this gets too expensive. - const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); - - // Assume that anything declared with a forward declaration and no - // @interface subclasses NSObject. - if (ID->isForwardDecl()) - return true; - - IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); - - for ( ; ID ; ID = ID->getSuperClass()) - if (ID->getIdentifier() == NSObjectII) - return true; - - return false; -} - -bool RetainSummaryManager::isTrackedCFObjectType(QualType T) { - return isRefType(T, "CF") || // Core Foundation. - isRefType(T, "CG") || // Core Graphics. - isRefType(T, "DADisk") || // Disk Arbitration API. - isRefType(T, "DADissenter") || - isRefType(T, "DASessionRef"); -} - -//===----------------------------------------------------------------------===// // Summary creation for functions (largely uses of Core Foundation). //===----------------------------------------------------------------------===// -static bool isRetain(FunctionDecl* FD, const char* FName) { - const char* loc = strstr(FName, "Retain"); - return loc && loc[sizeof("Retain")-1] == '\0'; +static bool isRetain(FunctionDecl* FD, StringRef FName) { + return FName.endswith("Retain"); } -static bool isRelease(FunctionDecl* FD, const char* FName) { - const char* loc = strstr(FName, "Release"); - return loc && loc[sizeof("Release")-1] == '\0'; +static bool isRelease(FunctionDecl* FD, StringRef FName) { + return FName.endswith("Release"); } RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { @@ -1152,12 +953,12 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { const IdentifierInfo *II = FD->getIdentifier(); if (!II) break; - - const char* FName = II->getNameStart(); + + StringRef FName = II->getName(); // Strip away preceding '_'. Doing this here will effect all the checks // down below. - while (*FName == '_') ++FName; + FName = FName.substr(FName.find_first_not_of('_')); // Inspect the result type. QualType RetTy = FT->getResultType(); @@ -1165,133 +966,63 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // FIXME: This should all be refactored into a chain of "summary lookup" // filters. assert(ScratchArgs.isEmpty()); - - switch (strlen(FName)) { - default: break; - case 14: - if (!memcmp(FName, "pthread_create", 14)) { - // Part of: <rdar://problem/7299394>. This will be addressed - // better with IPA. - S = getPersistentStopSummary(); - } - break; - - case 17: - // Handle: id NSMakeCollectable(CFTypeRef) - if (!memcmp(FName, "NSMakeCollectable", 17)) { - S = (RetTy->isObjCIdType()) - ? getUnarySummary(FT, cfmakecollectable) - : getPersistentStopSummary(); - } - else if (!memcmp(FName, "IOBSDNameMatching", 17) || - !memcmp(FName, "IOServiceMatching", 17)) { - // Part of <rdar://problem/6961230>. (IOKit) - // This should be addressed using a API table. - S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), - DoNothing, DoNothing); - } - break; - - case 21: - if (!memcmp(FName, "IOServiceNameMatching", 21)) { - // Part of <rdar://problem/6961230>. (IOKit) - // This should be addressed using a API table. - S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), - DoNothing, DoNothing); - } - break; - - case 24: - if (!memcmp(FName, "IOServiceAddNotification", 24)) { - // Part of <rdar://problem/6961230>. (IOKit) - // This should be addressed using a API table. - ScratchArgs = AF.Add(ScratchArgs, 2, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,DoNothing); - } - break; - - case 25: - if (!memcmp(FName, "IORegistryEntryIDMatching", 25)) { - // Part of <rdar://problem/6961230>. (IOKit) - // This should be addressed using a API table. - S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), - DoNothing, DoNothing); - } - break; - - case 26: - if (!memcmp(FName, "IOOpenFirmwarePathMatching", 26)) { - // Part of <rdar://problem/6961230>. (IOKit) - // This should be addressed using a API table. - S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), - DoNothing, DoNothing); - } - break; - - case 27: - if (!memcmp(FName, "IOServiceGetMatchingService", 27)) { - // Part of <rdar://problem/6961230>. - // This should be addressed using a API table. - ScratchArgs = AF.Add(ScratchArgs, 1, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); - } - break; - case 28: - if (!memcmp(FName, "IOServiceGetMatchingServices", 28)) { - // FIXES: <rdar://problem/6326900> - // This should be addressed using a API table. This strcmp is also - // a little gross, but there is no need to super optimize here. - ScratchArgs = AF.Add(ScratchArgs, 1, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, - DoNothing); - } - else if (!memcmp(FName, "CVPixelBufferCreateWithBytes", 28)) { - // FIXES: <rdar://problem/7283567> - // Eventually this can be improved by recognizing that the pixel - // buffer passed to CVPixelBufferCreateWithBytes is released via - // a callback and doing full IPA to make sure this is done correctly. - // FIXME: This function has an out parameter that returns an - // allocated object. - ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, - DoNothing); - } - break; - - case 29: - if (!memcmp(FName, "CGBitmapContextCreateWithData", 29)) { - // FIXES: <rdar://problem/7358899> - // Eventually this can be improved by recognizing that 'releaseInfo' - // passed to CGBitmapContextCreateWithData is released via - // a callback and doing full IPA to make sure this is done correctly. - ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking); - S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), - DoNothing,DoNothing); - } - break; - - case 32: - if (!memcmp(FName, "IOServiceAddMatchingNotification", 32)) { - // Part of <rdar://problem/6961230>. - // This should be addressed using a API table. - ScratchArgs = AF.Add(ScratchArgs, 2, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); - } - break; - - case 34: - if (!memcmp(FName, "CVPixelBufferCreateWithPlanarBytes", 34)) { - // FIXES: <rdar://problem/7283567> - // Eventually this can be improved by recognizing that the pixel - // buffer passed to CVPixelBufferCreateWithPlanarBytes is released - // via a callback and doing full IPA to make sure this is done - // correctly. - ScratchArgs = AF.Add(ScratchArgs, 12, StopTracking); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, - DoNothing); - } - break; + if (FName == "pthread_create") { + // Part of: <rdar://problem/7299394>. This will be addressed + // better with IPA. + S = getPersistentStopSummary(); + } else if (FName == "NSMakeCollectable") { + // Handle: id NSMakeCollectable(CFTypeRef) + S = (RetTy->isObjCIdType()) + ? getUnarySummary(FT, cfmakecollectable) + : getPersistentStopSummary(); + } else if (FName == "IOBSDNameMatching" || + FName == "IOServiceMatching" || + FName == "IOServiceNameMatching" || + FName == "IORegistryEntryIDMatching" || + FName == "IOOpenFirmwarePathMatching") { + // Part of <rdar://problem/6961230>. (IOKit) + // This should be addressed using a API table. + S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), + DoNothing, DoNothing); + } else if (FName == "IOServiceGetMatchingService" || + FName == "IOServiceGetMatchingServices") { + // FIXES: <rdar://problem/6326900> + // This should be addressed using a API table. This strcmp is also + // a little gross, but there is no need to super optimize here. + ScratchArgs = AF.Add(ScratchArgs, 1, DecRef); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + } else if (FName == "IOServiceAddNotification" || + FName == "IOServiceAddMatchingNotification") { + // Part of <rdar://problem/6961230>. (IOKit) + // This should be addressed using a API table. + ScratchArgs = AF.Add(ScratchArgs, 2, DecRef); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + } else if (FName == "CVPixelBufferCreateWithBytes") { + // FIXES: <rdar://problem/7283567> + // Eventually this can be improved by recognizing that the pixel + // buffer passed to CVPixelBufferCreateWithBytes is released via + // a callback and doing full IPA to make sure this is done correctly. + // FIXME: This function has an out parameter that returns an + // allocated object. + ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + } else if (FName == "CGBitmapContextCreateWithData") { + // FIXES: <rdar://problem/7358899> + // Eventually this can be improved by recognizing that 'releaseInfo' + // passed to CGBitmapContextCreateWithData is released via + // a callback and doing full IPA to make sure this is done correctly. + ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking); + S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), + DoNothing, DoNothing); + } else if (FName == "CVPixelBufferCreateWithPlanarBytes") { + // FIXES: <rdar://problem/7283567> + // Eventually this can be improved by recognizing that the pixel + // buffer passed to CVPixelBufferCreateWithPlanarBytes is released + // via a callback and doing full IPA to make sure this is done + // correctly. + ScratchArgs = AF.Add(ScratchArgs, 12, StopTracking); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } // Did we get a summary? @@ -1312,10 +1043,10 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { if (RetTy->isPointerType()) { // For CoreFoundation ('CF') types. - if (isRefType(RetTy, "CF", &Ctx, FName)) { + if (cocoa::isRefType(RetTy, "CF", FName)) { if (isRetain(FD, FName)) S = getUnarySummary(FT, cfretain); - else if (strstr(FName, "MakeCollectable")) + else if (FName.find("MakeCollectable") != StringRef::npos) S = getUnarySummary(FT, cfmakecollectable); else S = getCFCreateGetRuleSummary(FD, FName); @@ -1324,7 +1055,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { } // For CoreGraphics ('CG') types. - if (isRefType(RetTy, "CG", &Ctx, FName)) { + if (cocoa::isRefType(RetTy, "CG", FName)) { if (isRetain(FD, FName)) S = getUnarySummary(FT, cfretain); else @@ -1334,9 +1065,9 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { } // For the Disk Arbitration API (DiskArbitration/DADisk.h) - if (isRefType(RetTy, "DADisk") || - isRefType(RetTy, "DADissenter") || - isRefType(RetTy, "DASessionRef")) { + if (cocoa::isRefType(RetTy, "DADisk") || + cocoa::isRefType(RetTy, "DADissenter") || + cocoa::isRefType(RetTy, "DASessionRef")) { S = getCFCreateGetRuleSummary(FD, FName); break; } @@ -1348,10 +1079,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // about that don't return a pointer type. if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) { // Test for 'CGCF'. - if (FName[1] == 'G' && FName[2] == 'C' && FName[3] == 'F') - FName += 4; - else - FName += 2; + FName = FName.substr(FName.startswith("CGCF") ? 4 : 2); if (isRelease(FD, FName)) S = getUnarySummary(FT, cfrelease); @@ -1398,12 +1126,13 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { RetainSummary* RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD, - const char* FName) { + StringRef FName) { - if (strstr(FName, "Create") || strstr(FName, "Copy")) + if (FName.find("Create") != StringRef::npos || + FName.find("Copy") != StringRef::npos) return getCFSummaryCreateRule(FD); - if (strstr(FName, "Get")) + if (FName.find("Get") != StringRef::npos) return getCFSummaryGetRule(FD); return getDefaultSummary(); @@ -1471,7 +1200,7 @@ RetainSummaryManager::getInitMethodSummary(QualType RetTy) { assert(ScratchArgs.isEmpty()); // 'init' methods conceptually return a newly allocated object and claim // the receiver. - if (isTrackedObjCObjectType(RetTy) || isTrackedCFObjectType(RetTy)) + if (cocoa::isCocoaObjectRef(RetTy) || cocoa::isCFObjectRef(RetTy)) return getPersistentSummary(ObjCInitRetE, DecRefMsg); return getDefaultSummary(); @@ -1486,7 +1215,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, QualType RetTy = FD->getResultType(); // Determine if there is a special return effect for this method. - if (isTrackedObjCObjectType(RetTy)) { + if (cocoa::isCocoaObjectRef(RetTy)) { if (FD->getAttr<NSReturnsRetainedAttr>()) { Summ.setRetEffect(ObjCAllocRetE); } @@ -1510,7 +1239,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, bool isTrackedLoc = false; // Determine if there is a special return effect for this method. - if (isTrackedObjCObjectType(MD->getResultType())) { + if (cocoa::isCocoaObjectRef(MD->getResultType())) { if (MD->getAttr<NSReturnsRetainedAttr>()) { Summ.setRetEffect(ObjCAllocRetE); return; @@ -1560,18 +1289,18 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, } // Look for methods that return an owned object. - if (isTrackedObjCObjectType(RetTy)) { + if (cocoa::isCocoaObjectRef(RetTy)) { // EXPERIMENTAL: Assume the Cocoa conventions for all objects returned // by instance methods. - RetEffect E = followsFundamentalRule(S) + RetEffect E = cocoa::followsFundamentalRule(S) ? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC); return getPersistentSummary(E, ReceiverEff, MayEscape); } // Look for methods that return an owned core foundation object. - if (isTrackedCFObjectType(RetTy)) { - RetEffect E = followsFundamentalRule(S) + if (cocoa::isCFObjectRef(RetTy)) { + RetEffect E = cocoa::followsFundamentalRule(S) ? RetEffect::MakeOwned(RetEffect::CF, true) : RetEffect::MakeNotOwned(RetEffect::CF); @@ -1653,7 +1382,7 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S, assert(ScratchArgs.isEmpty()); // "initXXX": pass-through for receiver. - if (deriveNamingConvention(S) == InitRule) + if (cocoa::deriveNamingConvention(S) == cocoa::InitRule) Summ = getInitMethodSummary(RetTy); else Summ = getCommonMethodSummary(MD, S, RetTy); @@ -2880,10 +2609,12 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, StoreManager::InvalidatedSymbols IS; - state = StoreMgr.InvalidateRegions(state, RegionsToInvalidate.data(), + Store store = state->getStore(); + store = StoreMgr.InvalidateRegions(store, RegionsToInvalidate.data(), RegionsToInvalidate.data() + RegionsToInvalidate.size(), Ex, Count, &IS); + state = state->makeWithStore(store); for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), E = IS.end(); I!=E; ++I) { // Remove any existing reference-count binding. diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt new file mode 100644 index 000000000000..7b21d08dcb71 --- /dev/null +++ b/lib/Checker/CMakeLists.txt @@ -0,0 +1,67 @@ +set(LLVM_NO_RTTI 1) + +add_clang_library(clangChecker + AdjustedReturnValueChecker.cpp + ArrayBoundChecker.cpp + AttrNonNullChecker.cpp + BasicConstraintManager.cpp + BasicObjCFoundationChecks.cpp + BasicStore.cpp + BasicValueFactory.cpp + BugReporter.cpp + BugReporterVisitors.cpp + BuiltinFunctionChecker.cpp + CFRefCount.cpp + CallAndMessageChecker.cpp + CallInliner.cpp + CastToStructChecker.cpp + CheckDeadStores.cpp + CheckObjCDealloc.cpp + CheckObjCInstMethSignature.cpp + CheckObjCUnusedIVars.cpp + CheckSecuritySyntaxOnly.cpp + CheckSizeofPointer.cpp + Checker.cpp + CocoaConventions.cpp + DereferenceChecker.cpp + DivZeroChecker.cpp + Environment.cpp + ExplodedGraph.cpp + FixedAddressChecker.cpp + FlatStore.cpp + GRBlockCounter.cpp + GRCoreEngine.cpp + GRExprEngine.cpp + GRExprEngineExperimentalChecks.cpp + GRState.cpp + LLVMConventionsChecker.cpp + MallocChecker.cpp + ManagerRegistry.cpp + MemRegion.cpp + NSAutoreleasePoolChecker.cpp + NSErrorChecker.cpp + NoReturnFunctionChecker.cpp + OSAtomicChecker.cpp + PathDiagnostic.cpp + PointerArithChecker.cpp + PointerSubChecker.cpp + PthreadLockChecker.cpp + RangeConstraintManager.cpp + RegionStore.cpp + ReturnPointerRangeChecker.cpp + ReturnStackAddressChecker.cpp + ReturnUndefChecker.cpp + SVals.cpp + SValuator.cpp + SimpleConstraintManager.cpp + SimpleSValuator.cpp + Store.cpp + SymbolManager.cpp + UndefBranchChecker.cpp + UndefCapturedBlockVarChecker.cpp + UndefResultChecker.cpp + UndefinedArraySubscriptChecker.cpp + UndefinedAssignmentChecker.cpp + VLASizeChecker.cpp + ValueManager.cpp + ) diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp index c287354650b8..9013c3818b0c 100644 --- a/lib/Analysis/CallAndMessageChecker.cpp +++ b/lib/Checker/CallAndMessageChecker.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/TargetInfo.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/BugReporter/BugReporter.h" #include "clang/AST/ParentMap.h" #include "GRExprEngineInternalChecks.h" diff --git a/lib/Analysis/CallInliner.cpp b/lib/Checker/CallInliner.cpp index d18bbcc0174a..d94994b19437 100644 --- a/lib/Analysis/CallInliner.cpp +++ b/lib/Checker/CallInliner.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/LocalCheckers.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/Checkers/LocalCheckers.h" using namespace clang; diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp index 219c09f6ab7a..bef5bc285ee2 100644 --- a/lib/Analysis/CastToStructChecker.cpp +++ b/lib/Checker/CastToStructChecker.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" using namespace clang; diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Checker/CheckDeadStores.cpp index 6e4d8998620d..4a7ca705488a 100644 --- a/lib/Analysis/CheckDeadStores.cpp +++ b/lib/Checker/CheckDeadStores.cpp @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/LocalCheckers.h" +#include "clang/Checker/Checkers/LocalCheckers.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Basic/Diagnostic.h" #include "clang/AST/ASTContext.h" diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp index 87c1f270a65c..d9606f1306d4 100644 --- a/lib/Analysis/CheckObjCDealloc.cpp +++ b/lib/Checker/CheckObjCDealloc.cpp @@ -13,9 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Checker/Checkers/LocalCheckers.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/BugReporter/BugReporter.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/DeclObjC.h" diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Checker/CheckObjCInstMethSignature.cpp index 10ba896557df..8c43a45d92c0 100644 --- a/lib/Analysis/CheckObjCInstMethSignature.cpp +++ b/lib/Checker/CheckObjCInstMethSignature.cpp @@ -13,9 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Checker/Checkers/LocalCheckers.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/BugReporter/BugReporter.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Type.h" #include "clang/AST/ASTContext.h" diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Checker/CheckObjCUnusedIVars.cpp index d4067c900f3f..f2cf58191632 100644 --- a/lib/Analysis/CheckObjCUnusedIVars.cpp +++ b/lib/Checker/CheckObjCUnusedIVars.cpp @@ -13,9 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Checker/Checkers/LocalCheckers.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/BugReporter/BugReporter.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/DeclObjC.h" diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp index f4874a5dfe4c..923baf50f3f6 100644 --- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp +++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/TargetInfo.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/LocalCheckers.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/Checkers/LocalCheckers.h" #include "clang/AST/StmtVisitor.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Checker/CheckSizeofPointer.cpp index 4f5da9f5a716..bbe494c99da5 100644 --- a/lib/Analysis/CheckSizeofPointer.cpp +++ b/lib/Checker/CheckSizeofPointer.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Checker/BugReporter/BugReporter.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Analysis/LocalCheckers.h" +#include "clang/Checker/Checkers/LocalCheckers.h" using namespace clang; diff --git a/lib/Analysis/Checker.cpp b/lib/Checker/Checker.cpp index fb9d04d947b7..36323b9efb61 100644 --- a/lib/Analysis/Checker.cpp +++ b/lib/Checker/Checker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Checker/PathSensitive/Checker.h" using namespace clang; Checker::~Checker() {} diff --git a/lib/Checker/CocoaConventions.cpp b/lib/Checker/CocoaConventions.cpp new file mode 100644 index 000000000000..3ba887ccc7e3 --- /dev/null +++ b/lib/Checker/CocoaConventions.cpp @@ -0,0 +1,195 @@ +//===- CocoaConventions.h - Special handling of Cocoa conventions -*- 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/DomainSpecific/CocoaConventions.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "llvm/ADT/StringExtras.h" + +using namespace clang; + +using llvm::StringRef; + +// The "fundamental rule" for naming conventions of methods: +// (url broken into two lines) +// http://developer.apple.com/documentation/Cocoa/Conceptual/ +// MemoryMgmt/Tasks/MemoryManagementRules.html +// +// "You take ownership of an object if you create it using a method whose name +// begins with "alloc" or "new" or contains "copy" (for example, alloc, +// newObject, or mutableCopy), or if you send it a retain message. You are +// responsible for relinquishing ownership of objects you own using release +// or autorelease. Any other time you receive an object, you must +// not release it." +// + +static bool isWordEnd(char ch, char prev, char next) { + return ch == '\0' + || (islower(prev) && isupper(ch)) // xxxC + || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate + || !isalpha(ch); +} + +static const char* parseWord(const char* s) { + char ch = *s, prev = '\0'; + assert(ch != '\0'); + char next = *(s+1); + while (!isWordEnd(ch, prev, next)) { + prev = ch; + ch = next; + next = *((++s)+1); + } + return s; +} + +cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) { + IdentifierInfo *II = S.getIdentifierInfoForSlot(0); + + if (!II) + return NoConvention; + + const char *s = II->getNameStart(); + + // A method/function name may contain a prefix. We don't know it is there, + // however, until we encounter the first '_'. + bool InPossiblePrefix = true; + bool AtBeginning = true; + NamingConvention C = NoConvention; + + while (*s != '\0') { + // Skip '_'. + if (*s == '_') { + if (InPossiblePrefix) { + // If we already have a convention, return it. Otherwise, skip + // the prefix as if it wasn't there. + if (C != NoConvention) + break; + + InPossiblePrefix = false; + AtBeginning = true; + assert(C == NoConvention); + } + ++s; + continue; + } + + // Skip numbers, ':', etc. + if (!isalpha(*s)) { + ++s; + continue; + } + + const char *wordEnd = parseWord(s); + assert(wordEnd > s); + unsigned len = wordEnd - s; + + switch (len) { + default: + break; + case 3: + // Methods starting with 'new' follow the create rule. + if (AtBeginning && StringRef(s, len).equals_lower("new")) + C = CreateRule; + break; + case 4: + // Methods starting with 'alloc' or contain 'copy' follow the + // create rule + if (C == NoConvention && StringRef(s, len).equals_lower("copy")) + C = CreateRule; + else // Methods starting with 'init' follow the init rule. + if (AtBeginning && StringRef(s, len).equals_lower("init")) + C = InitRule; + break; + case 5: + if (AtBeginning && StringRef(s, len).equals_lower("alloc")) + C = CreateRule; + break; + } + + // If we aren't in the prefix and have a derived convention then just + // return it now. + if (!InPossiblePrefix && C != NoConvention) + return C; + + AtBeginning = false; + s = wordEnd; + } + + // We will get here if there wasn't more than one word + // after the prefix. + return C; +} + +bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix, + llvm::StringRef Name) { + // Recursively walk the typedef stack, allowing typedefs of reference types. + while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { + llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName(); + if (TDName.startswith(Prefix) && TDName.endswith("Ref")) + return true; + + RetTy = TD->getDecl()->getUnderlyingType(); + } + + if (Name.empty()) + return false; + + // Is the type void*? + const PointerType* PT = RetTy->getAs<PointerType>(); + if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType())) + return false; + + // Does the name start with the prefix? + return Name.startswith(Prefix); +} + +bool cocoa::isCFObjectRef(QualType T) { + return isRefType(T, "CF") || // Core Foundation. + isRefType(T, "CG") || // Core Graphics. + isRefType(T, "DADisk") || // Disk Arbitration API. + isRefType(T, "DADissenter") || + isRefType(T, "DASessionRef"); +} + + +bool cocoa::isCocoaObjectRef(QualType Ty) { + if (!Ty->isObjCObjectPointerType()) + return false; + + const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>(); + + // Can be true for objects with the 'NSObject' attribute. + if (!PT) + return true; + + // We assume that id<..>, id, and "Class" all represent tracked objects. + if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || + PT->isObjCClassType()) + return true; + + // Does the interface subclass NSObject? + // FIXME: We can memoize here if this gets too expensive. + const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); + + // Assume that anything declared with a forward declaration and no + // @interface subclasses NSObject. + if (ID->isForwardDecl()) + return true; + + for ( ; ID ; ID = ID->getSuperClass()) + if (ID->getIdentifier()->getName() == "NSObject") + return true; + + return false; +} diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Checker/DereferenceChecker.cpp index 98243874d7d9..0cbc4086701a 100644 --- a/lib/Analysis/DereferenceChecker.cpp +++ b/lib/Checker/DereferenceChecker.cpp @@ -12,10 +12,10 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" -#include "clang/Analysis/PathSensitive/Checker.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/BugReporter.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; diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Checker/DivZeroChecker.cpp index 266c23609422..e1346e11b6fd 100644 --- a/lib/Analysis/DivZeroChecker.cpp +++ b/lib/Checker/DivZeroChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" using namespace clang; diff --git a/lib/Analysis/Environment.cpp b/lib/Checker/Environment.cpp index f04cf7b05fed..c2c9190fc9ff 100644 --- a/lib/Analysis/Environment.cpp +++ b/lib/Checker/Environment.cpp @@ -10,7 +10,7 @@ // This file defined the Environment and EnvironmentManager classes. // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRState.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "llvm/ADT/ImmutableMap.h" diff --git a/lib/Analysis/ExplodedGraph.cpp b/lib/Checker/ExplodedGraph.cpp index 3b339ffc0dfe..20429b951992 100644 --- a/lib/Analysis/ExplodedGraph.cpp +++ b/lib/Checker/ExplodedGraph.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/ExplodedGraph.h" -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/ExplodedGraph.h" +#include "clang/Checker/PathSensitive/GRState.h" #include "clang/AST/Stmt.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseMap.h" diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Checker/FixedAddressChecker.cpp index 031ca44b602e..04c17d6d7abb 100644 --- a/lib/Analysis/FixedAddressChecker.cpp +++ b/lib/Checker/FixedAddressChecker.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" using namespace clang; diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp new file mode 100644 index 000000000000..dac66def5dc9 --- /dev/null +++ b/lib/Checker/FlatStore.cpp @@ -0,0 +1,166 @@ +//=== FlatStore.cpp - Flat region-based store model -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/GRState.h" +#include "llvm/ADT/ImmutableIntervalMap.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; +using llvm::Interval; + +// The actual store type. +typedef llvm::ImmutableIntervalMap<SVal> BindingVal; +typedef llvm::ImmutableMap<const MemRegion *, BindingVal> RegionBindings; + +namespace { +class FlatStoreManager : public StoreManager { + RegionBindings::Factory RBFactory; + BindingVal::Factory BVFactory; + +public: + FlatStoreManager(GRStateManager &mgr) + : StoreManager(mgr), + RBFactory(mgr.getAllocator()), + BVFactory(mgr.getAllocator()) {} + + SVal Retrieve(Store store, Loc L, QualType T); + Store Bind(Store store, Loc L, SVal val); + Store Remove(Store St, Loc L); + Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* cl, + const LocationContext *LC, SVal v); + + Store getInitialStore(const LocationContext *InitLoc) { + return RBFactory.GetEmptyMap().getRoot(); + } + + SubRegionMap *getSubRegionMap(Store store) { + return 0; + } + + SVal ArrayToPointer(Loc Array); + Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper, + llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){ + return store; + } + + Store BindDecl(Store store, const VarRegion *VR, SVal initVal); + + Store BindDeclWithNoInit(Store store, const VarRegion *VR); + + typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols; + + Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E, + unsigned Count, InvalidatedSymbols *IS); + + void print(Store store, llvm::raw_ostream& Out, const char* nl, + const char *sep); + void iterBindings(Store store, BindingsHandler& f); + +private: + static RegionBindings getRegionBindings(Store store) { + return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store)); + } + + Interval RegionToInterval(const MemRegion *R); + + SVal RetrieveRegionWithNoBinding(const MemRegion *R, QualType T); +}; +} // end anonymous namespace + +StoreManager *clang::CreateFlatStoreManager(GRStateManager &StMgr) { + return new FlatStoreManager(StMgr); +} + +SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) { + const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion(); + Interval I = RegionToInterval(R); + RegionBindings B = getRegionBindings(store); + const BindingVal *BV = B.lookup(R); + if (BV) { + const SVal *V = BVFactory.Lookup(*BV, I); + if (V) + return *V; + else + return RetrieveRegionWithNoBinding(R, T); + } + return RetrieveRegionWithNoBinding(R, T); +} + +SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R, + QualType T) { + if (R->hasStackNonParametersStorage()) + return UndefinedVal(); + else + return ValMgr.getRegionValueSymbolVal(R, T); +} + +Store FlatStoreManager::Bind(Store store, Loc L, SVal val) { + const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion(); + RegionBindings B = getRegionBindings(store); + const BindingVal *V = B.lookup(R); + + BindingVal BV = BVFactory.GetEmptyMap(); + if (V) + BV = *V; + + Interval I = RegionToInterval(R); + BV = BVFactory.Add(BV, I, val); + B = RBFactory.Add(B, R, BV); + return B.getRoot(); +} + +Store FlatStoreManager::Remove(Store store, Loc L) { + return store; +} + +Store FlatStoreManager::BindCompoundLiteral(Store store, + const CompoundLiteralExpr* cl, + const LocationContext *LC, + SVal v) { + return store; +} + +SVal FlatStoreManager::ArrayToPointer(Loc Array) { + return Array; +} + +Store FlatStoreManager::BindDecl(Store store, const VarRegion *VR, + SVal initVal) { + return store; +} + +Store FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR) { + return store; +} + +Store FlatStoreManager::InvalidateRegion(Store store, const MemRegion *R, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS) { + return store; +} + +void FlatStoreManager::print(Store store, llvm::raw_ostream& Out, + const char* nl, const char *sep) { +} + +void FlatStoreManager::iterBindings(Store store, BindingsHandler& f) { +} + +Interval FlatStoreManager::RegionToInterval(const MemRegion *R) { + switch (R->getKind()) { + case MemRegion::VarRegionKind: { + QualType T = cast<VarRegion>(R)->getValueType(Ctx); + uint64_t Size = Ctx.getTypeSize(T); + return Interval(0, Size-1); + } + default: + llvm_unreachable("Region kind unhandled."); + return Interval(0, 0); + } +} diff --git a/lib/Analysis/GRBlockCounter.cpp b/lib/Checker/GRBlockCounter.cpp index 4f4103ac45b4..3fa3e1ebb9c6 100644 --- a/lib/Analysis/GRBlockCounter.cpp +++ b/lib/Checker/GRBlockCounter.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/GRBlockCounter.h" +#include "clang/Checker/PathSensitive/GRBlockCounter.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index 209452a3927a..d54b0777eda7 100644 --- a/lib/Analysis/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/GRCoreEngine.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Checker/PathSensitive/GRCoreEngine.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/AST/Expr.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/DenseMap.h" diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 8f8d859e0ca0..7f863193743b 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -12,11 +12,10 @@ // functions and build the ExplodedGraph at the expression level. // //===----------------------------------------------------------------------===// - #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" -#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h" +#include "clang/Checker/PathSensitive/Checker.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" @@ -48,7 +47,7 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { } -static QualType GetCalleeReturnType(const CallExpr *CE) { +static QualType GetCalleeReturnType(const CallExpr *CE) { const Expr *Callee = CE->getCallee(); QualType T = Callee->getType(); if (const PointerType *PT = T->getAs<PointerType>()) { @@ -62,7 +61,7 @@ static QualType GetCalleeReturnType(const CallExpr *CE) { return T; } -static bool CalleeReturnsReference(const CallExpr *CE) { +static bool CalleeReturnsReference(const CallExpr *CE) { return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>(); } @@ -177,10 +176,10 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, else { CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; CurrSet->clear(); - } + } void *tag = I->first; Checker *checker = I->second; - + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); NI != NE; ++NI) checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit); @@ -191,7 +190,7 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, // automatically. } -void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, +void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, ExplodedNodeSet &Dst, const GRState *state, ExplodedNode *Pred) { @@ -220,8 +219,8 @@ void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, // CheckerEvalCall returns true if one of the checkers processed the node. // This may return void when all call evaluation logic goes to some checker // in the future. -bool GRExprEngine::CheckerEvalCall(const CallExpr *CE, - ExplodedNodeSet &Dst, +bool GRExprEngine::CheckerEvalCall(const CallExpr *CE, + ExplodedNodeSet &Dst, ExplodedNode *Pred) { bool Evaluated = false; ExplodedNodeSet DstTmp; @@ -246,21 +245,21 @@ bool GRExprEngine::CheckerEvalCall(const CallExpr *CE, return Evaluated; } -// FIXME: This is largely copy-paste from CheckerVisit(). Need to +// FIXME: This is largely copy-paste from CheckerVisit(). Need to // unify. void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, SVal location, SVal val, bool isPrevisit) { - + if (Checkers.empty()) { Dst.insert(Src); return; } - + ExplodedNodeSet Tmp; ExplodedNodeSet *PrevSet = &Src; - + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) { ExplodedNodeSet *CurrSet = 0; @@ -273,16 +272,16 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, void *tag = I->first; Checker *checker = I->second; - + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); NI != NE; ++NI) checker->GR_VisitBind(*CurrSet, *Builder, *this, AssignE, StoreE, *NI, tag, location, val, isPrevisit); - + // Update which NodeSet is the current one. PrevSet = CurrSet; } - + // Don't autotransition. The CheckerContext objects should do this // automatically. } @@ -300,7 +299,8 @@ static void RegisterInternalChecks(GRExprEngine &Eng) { // explicitly registered with the BugReporter. If they issue any BugReports, // their associated BugType will get registered with the BugReporter // automatically. Note that the check itself is owned by the GRExprEngine - // object. + // object. + RegisterAdjustedReturnValueChecker(Eng); RegisterAttrNonNullChecker(Eng); RegisterCallAndMessageChecker(Eng); RegisterDereferenceChecker(Eng); @@ -311,6 +311,7 @@ static void RegisterInternalChecks(GRExprEngine &Eng) { RegisterUndefinedArraySubscriptChecker(Eng); RegisterUndefinedAssignmentChecker(Eng); RegisterUndefBranchChecker(Eng); + RegisterUndefCapturedBlockVarChecker(Eng); RegisterUndefResultChecker(Eng); // This is not a checker yet. @@ -336,7 +337,7 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf) BR(mgr, *this), TF(tf) { // Register internal checks. RegisterInternalChecks(*this); - + // FIXME: Eventually remove the TF object entirely. TF->RegisterChecks(*this); TF->RegisterPrinters(getStateManager().Printers); @@ -375,7 +376,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { // FIXME: It would be nice if we had a more general mechanism to add // such preconditions. Some day. do { - const Decl *D = InitLoc->getDecl(); + const Decl *D = InitLoc->getDecl(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // Precondition: the first argument of 'main' is an integer guaranteed // to be > 0. @@ -387,11 +388,11 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { QualType T = PD->getType(); if (!T->isIntegerType()) break; - + const MemRegion *R = state->getRegion(PD, InitLoc); if (!R) break; - + SVal V = state->getSVal(loc::MemRegionVal(R)); SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V, ValMgr.makeZeroVal(T), @@ -399,23 +400,23 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { DefinedOrUnknownSVal *Constraint = dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested); - + if (!Constraint) break; - + if (const GRState *newState = state->Assume(*Constraint, true)) state = newState; - + break; } - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { // Precondition: 'self' is always non-null upon entry to an Objective-C // method. const ImplicitParamDecl *SelfD = MD->getSelfDecl(); const MemRegion *R = state->getRegion(SelfD, InitLoc); SVal V = state->getSVal(loc::MemRegionVal(R)); - + if (const Loc *LV = dyn_cast<Loc>(&V)) { // Assume that the pointer value in 'self' is non-null. state = state->Assume(*LV, true); @@ -423,7 +424,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { } } } while (0); - + return state; } @@ -434,19 +435,19 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { /// EvalAssume - Called by ConstraintManager. Used to call checker-specific /// logic for handling assumptions on symbolic values. const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond, - bool assumption) { + bool assumption) { for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); I != E; ++I) { if (!state) - return NULL; - + return NULL; + state = I->second->EvalAssume(state, cond, assumption); } - + if (!state) return NULL; - + return TF->EvalAssume(state, cond, assumption); } @@ -615,7 +616,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::AsmStmtClass: VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst); break; - + case Stmt::BlockDeclRefExprClass: VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), Pred, Dst, false); break; @@ -637,7 +638,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } - if (AMgr.shouldEagerlyAssume() && + if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) { ExplodedNodeSet Tmp; VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false); @@ -695,7 +696,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { // This case isn't for branch processing, but for handling the // initialization of a condition variable. VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst); - break; + break; case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: { @@ -703,7 +704,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitCast(C, C->getSubExpr(), Pred, Dst, false); break; } - + case Stmt::IfStmtClass: // This case isn't for branch processing, but for handling the // initialization of a condition variable. @@ -775,7 +776,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::StringLiteralClass: VisitLValue(cast<StringLiteral>(S), Pred, Dst); break; - + case Stmt::SwitchStmtClass: // This case isn't for branch processing, but for handling the // initialization of a condition variable. @@ -793,18 +794,18 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitUnaryOperator(U, Pred, Dst, false); break; } - + case Stmt::WhileStmtClass: // This case isn't for branch processing, but for handling the // initialization of a condition variable. VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst); - break; + break; } } void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst) { - + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), Ex->getLocStart(), "Error evaluating statement"); @@ -836,27 +837,27 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::CompoundAssignOperatorClass: VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true); return; - + case Stmt::BlockDeclRefExprClass: VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true); return; - + case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: { CallExpr *C = cast<CallExpr>(Ex); assert(CalleeReturnsReferenceOrRecord(C)); - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true); break; } - + case Stmt::CompoundLiteralExprClass: VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true); - return; + return; case Stmt::DeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true); return; - + case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: { CastExpr *C = cast<CastExpr>(Ex); @@ -864,7 +865,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, VisitCast(C, C->getSubExpr(), Pred, Dst, true); break; } - + case Stmt::MemberExprClass: VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true); return; @@ -872,11 +873,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::ObjCIvarRefExprClass: VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true); return; - + case Stmt::ObjCMessageExprClass: { ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex); assert(ReceiverReturnsReferenceOrRecord(ME)); - VisitObjCMessageExpr(ME, Pred, Dst, true); + VisitObjCMessageExpr(ME, Pred, Dst, true); return; } @@ -911,7 +912,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::IntegerLiteralClass: CreateCXXTemporaryObject(Ex, Pred, Dst); return; - + default: // Arbitrary subexpressions can return aggregate temporaries that // can be used in a lvalue context. We need to enhance our support @@ -1083,7 +1084,7 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term, SVal recovered = RecoverCastedSymbol(getStateManager(), builder.getState(), Condition, getContext()); - + if (!recovered.isUnknown()) { X = recovered; } @@ -1165,7 +1166,7 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) { void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst) { - assert(Ex == CurrentStmt && + assert(Ex == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)); const GRState* state = GetState(Pred); @@ -1203,7 +1204,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { if (CondV_untested.isUndef()) { //ExplodedNode* N = builder.generateDefaultCaseNode(state, true); - // FIXME: add checker + // FIXME: add checker //UndefBranches.insert(N); return; @@ -1247,7 +1248,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt())); DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state, CondV, CaseVal); - + // Now "assume" that the case matches. if (const GRState* stateNew = state->Assume(Res, true)) { builder.generateCaseStmtNode(I, stateNew); @@ -1271,7 +1272,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { DefaultSt = NULL; } } - + // Concretize the next value in the range. if (V1.Val.getInt() == V2.Val.getInt()) break; @@ -1314,7 +1315,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, MakeNode(Dst, B, Pred, state->BindExpr(B, X)); return; } - + DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X); // We took the RHS. Because the value of the '&&' or '||' expression must @@ -1347,16 +1348,16 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - + ExplodedNodeSet Tmp; - + CanQualType T = getContext().getCanonicalType(BE->getType()); SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T, Pred->getLocationContext()); MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V), ProgramPoint::PostLValueKind); - + // Post-visit the BlockExpr. CheckerVisit(BE, Dst, Tmp, false); } @@ -1391,7 +1392,7 @@ void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D, else V = UnknownVal(); } - + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), ProgramPoint::PostLValueKind); } @@ -1494,19 +1495,19 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE, Stmt* StoreE, ExplodedNode* Pred, const GRState* state, SVal location, SVal Val, bool atDeclInit) { - - + + // Do a previsit of the bind. ExplodedNodeSet CheckedSet, Src; Src.Add(Pred); CheckerVisitBind(AssignE, StoreE, CheckedSet, Src, location, Val, true); - + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { - + if (Pred != *I) state = GetState(*I); - + const GRState* newState = 0; if (atDeclInit) { @@ -1565,7 +1566,7 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE, SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind, ProgramPoint::PostStoreKind); SaveAndRestore<const void*> OldTag(Builder->Tag, tag); - + // Proceed with the store. for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val); @@ -1578,12 +1579,12 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred, // Are we loading from a region? This actually results in two loads; one // to fetch the address of the referenced value and one to fetch the // referenced value. - if (const TypedRegion *TR = + if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { - + QualType ValTy = TR->getValueType(getContext()); if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) { - static int loadReferenceTag = 0; + static int loadReferenceTag = 0; ExplodedNodeSet Tmp; EvalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag, getContext().getPointerType(RT->getPointeeType())); @@ -1593,11 +1594,11 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred, state = GetState(*I); location = state->getSVal(Ex); EvalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy); - } + } return; } } - + EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy); } @@ -1605,16 +1606,16 @@ void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred, const GRState* state, SVal location, const void *tag, QualType LoadTy) { - + // Evaluate the location (checks for bad dereferences). ExplodedNodeSet Tmp; EvalLocation(Tmp, Ex, Pred, state, location, tag, true); if (Tmp.empty()) return; - + assert(!location.isUndef()); - + SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind); SaveAndRestore<const void*> OldTag(Builder->Tag); @@ -1627,7 +1628,7 @@ void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex, ProgramPoint::PostLoadKind, tag); } else { - SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ? + SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ? Ex->getType() : LoadTy); MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind, tag); @@ -1644,11 +1645,11 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, Dst.Add(Pred); return; } - + ExplodedNodeSet Src, Tmp; Src.Add(Pred); ExplodedNodeSet *PrevSet = &Src; - + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) { ExplodedNodeSet *CurrSet = 0; @@ -1658,10 +1659,10 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; CurrSet->clear(); } - + void *tag = I->first; Checker *checker = I->second; - + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); NI != NE; ++NI) { // Use the 'state' argument only when the predecessor node is the @@ -1670,7 +1671,7 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, *NI == Pred ? state : GetState(*NI), location, tag, isLoad); } - + // Update which NodeSet is the current one. PrevSet = CurrSet; } @@ -1688,7 +1689,7 @@ public: CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n) : I(i), N(n) {} -}; +}; } // end anonymous namespace void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, @@ -1706,31 +1707,31 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, llvm::SmallVector<CallExprWLItem, 20> WorkList; WorkList.reserve(AE - AI); WorkList.push_back(CallExprWLItem(AI, Pred)); - + ExplodedNodeSet ArgsEvaluated; while (!WorkList.empty()) { CallExprWLItem Item = WorkList.back(); WorkList.pop_back(); - + if (Item.I == AE) { ArgsEvaluated.insert(Item.N); continue; } - + // Evaluate the argument. ExplodedNodeSet Tmp; const unsigned ParamIdx = Item.I - AI; - + bool VisitAsLvalue = false; if (Proto && ParamIdx < Proto->getNumArgs()) VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType(); - + if (VisitAsLvalue) VisitLValue(*Item.I, Item.N, Tmp); else Visit(*Item.I, Item.N, Tmp); - + // Enqueue evaluating the next argument on the worklist. ++(Item.I); @@ -1741,32 +1742,32 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, // Now process the call itself. ExplodedNodeSet DstTmp; Expr* Callee = CE->getCallee()->IgnoreParens(); - + for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(), NE=ArgsEvaluated.end(); NI != NE; ++NI) { // Evaluate the callee. ExplodedNodeSet DstTmp2; - Visit(Callee, *NI, DstTmp2); + Visit(Callee, *NI, DstTmp2); // Perform the previsit of the CallExpr, storing the results in DstTmp. CheckerVisit(CE, DstTmp, DstTmp2, true); } - + // Finally, evaluate the function call. We try each of the checkers // to see if the can evaluate the function call. ExplodedNodeSet DstTmp3; - + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI != DE; ++DI) { - + const GRState* state = GetState(*DI); SVal L = state->getSVal(Callee); - + // FIXME: Add support for symbolic function calls (calls involving // function pointer values that are symbolic). SaveAndRestore<bool> OldSink(Builder->BuildSinks); ExplodedNodeSet DstChecker; - + // If the callee is processed by a checker, skip the rest logic. if (CheckerEvalCall(CE, DstChecker, *DI)) DstTmp3.insert(DstChecker); @@ -1774,17 +1775,17 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), DE_Checker = DstChecker.end(); DI_Checker != DE_Checker; ++DI_Checker) { - + // Dispatch to the plug-in transfer function. unsigned OldSize = DstTmp3.size(); SaveOr OldHasGen(Builder->HasGeneratedNode); Pred = *DI_Checker; - + // Dispatch to transfer function logic to handle the call itself. // FIXME: Allow us to chain together transfer functions. - assert(Builder && "GRStmtNodeBuilder must be defined."); + assert(Builder && "GRStmtNodeBuilder must be defined."); getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, Pred); - + // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. if (!Builder->BuildSinks && DstTmp3.size() == OldSize && @@ -1793,24 +1794,24 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, } } } - + // Finally, perform the post-condition check of the CallExpr and store // the created nodes in 'Dst'. - + if (!(!asLValue && CalleeReturnsReference(CE))) { CheckerVisit(CE, Dst, DstTmp3, false); return; } - + // Handle the case where the called function returns a reference but // we expect an rvalue. For such cases, convert the reference to - // an rvalue. + // an rvalue. // FIXME: This conversion doesn't actually happen unless the result // of CallExpr is consumed by another expression. ExplodedNodeSet DstTmp4; CheckerVisit(CE, DstTmp4, DstTmp3, false); QualType LoadTy = CE->getType(); - + static int *ConvertToRvalueTag = 0; for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end(); NI!=NE; ++NI) { @@ -1950,10 +1951,10 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, Stmt* elem = S->getElement(); ExplodedNodeSet Tmp; EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false); - + if (Tmp.empty()) return; - + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { Pred = *NI; const GRState *state = GetState(Pred); @@ -1993,90 +1994,96 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, // Transfer function: Objective-C message expressions. //===----------------------------------------------------------------------===// +namespace { +class ObjCMsgWLItem { +public: + ObjCMessageExpr::arg_iterator I; + ExplodedNode *N; + + ObjCMsgWLItem(const ObjCMessageExpr::arg_iterator &i, ExplodedNode *n) + : I(i), N(n) {} +}; +} // end anonymous namespace + void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue){ - VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(), - Pred, Dst, asLValue); -} + // Create a worklist to process both the arguments. + llvm::SmallVector<ObjCMsgWLItem, 20> WL; -void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, - ObjCMessageExpr::arg_iterator AI, - ObjCMessageExpr::arg_iterator AE, - ExplodedNode* Pred, - ExplodedNodeSet& Dst, - bool asLValue) { - if (AI == AE) { + // But first evaluate the receiver (if any). + ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end(); + if (Expr *Receiver = ME->getReceiver()) { + ExplodedNodeSet Tmp; + Visit(Receiver, Pred, Tmp); - // Process the receiver. + if (Tmp.empty()) + return; - if (Expr* Receiver = ME->getReceiver()) { - ExplodedNodeSet Tmp; - Visit(Receiver, Pred, Tmp); + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) + WL.push_back(ObjCMsgWLItem(AI, *I)); + } + else + WL.push_back(ObjCMsgWLItem(AI, Pred)); - for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; - ++NI) - VisitObjCMessageExprDispatchHelper(ME, *NI, Dst, asLValue); + // Evaluate the arguments. + ExplodedNodeSet ArgsEvaluated; + while (!WL.empty()) { + ObjCMsgWLItem Item = WL.back(); + WL.pop_back(); - return; + if (Item.I == AE) { + ArgsEvaluated.insert(Item.N); + continue; } - VisitObjCMessageExprDispatchHelper(ME, Pred, Dst, asLValue); - return; - } - - ExplodedNodeSet Tmp; - Visit(*AI, Pred, Tmp); + // Evaluate the subexpression. + ExplodedNodeSet Tmp; - ++AI; + // FIXME: [Objective-C++] handle arguments that are references + Visit(*Item.I, Item.N, Tmp); - for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI) - VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst, asLValue); -} + // Enqueue evaluating the next argument on the worklist. + ++(Item.I); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) + WL.push_back(ObjCMsgWLItem(Item.I, *NI)); + } -void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, - ExplodedNode* Pred, - ExplodedNodeSet& Dst, - bool asLValue) { + // Now that the arguments are processed, handle the previsits checks. + ExplodedNodeSet DstPrevisit; + CheckerVisit(ME, DstPrevisit, ArgsEvaluated, true); - // Handle previsits checks. - ExplodedNodeSet Src, DstTmp; - Src.Add(Pred); - - CheckerVisit(ME, DstTmp, Src, true); - - ExplodedNodeSet PostVisitSrc; + // Proceed with evaluate the message expression. + ExplodedNodeSet DstEval; - for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); - DI!=DE; ++DI) { + for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(), + DE = DstPrevisit.end(); DI != DE; ++DI) { Pred = *DI; bool RaisesException = false; - - unsigned OldSize = PostVisitSrc.size(); + unsigned OldSize = DstEval.size(); SaveAndRestore<bool> OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->HasGeneratedNode); + SaveOr OldHasGen(Builder->HasGeneratedNode); if (const Expr *Receiver = ME->getReceiver()) { const GRState *state = Pred->getState(); // Bifurcate the state into nil and non-nil ones. - DefinedOrUnknownSVal receiverVal = + DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); const GRState *notNilState, *nilState; llvm::tie(notNilState, nilState) = state->Assume(receiverVal); - // There are three cases: can be nil or non-nil, must be nil, must be + // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We handle must be nil, and merge the rest two into non-nil. if (nilState && !notNilState) { - CheckerEvalNilReceiver(ME, PostVisitSrc, nilState, Pred); + CheckerEvalNilReceiver(ME, DstEval, nilState, Pred); continue; } - assert(notNilState); - // Check if the "raise" message was sent. + assert(notNilState); if (ME->getSelector() == RaiseSel) RaisesException = true; @@ -2086,7 +2093,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - EvalObjCMessageExpr(PostVisitSrc, ME, Pred, notNilState); + EvalObjCMessageExpr(DstEval, ME, Pred, notNilState); } else { IdentifierInfo* ClsName = ME->getClassName(); @@ -2104,7 +2111,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // Lazily create a cache of the selectors. if (!NSExceptionInstanceRaiseSelectors) { ASTContext& Ctx = getContext(); - NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; + NSExceptionInstanceRaiseSelectors = + new Selector[NUM_RAISE_SELECTORS]; llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; unsigned idx = 0; @@ -2133,36 +2141,35 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - EvalObjCMessageExpr(PostVisitSrc, ME, Pred, Builder->GetState(Pred)); + EvalObjCMessageExpr(DstEval, ME, Pred, Builder->GetState(Pred)); } - + // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && PostVisitSrc.size() == OldSize && + if (!Builder->BuildSinks && DstEval.size() == OldSize && !Builder->HasGeneratedNode) - MakeNode(PostVisitSrc, ME, Pred, GetState(Pred)); + MakeNode(DstEval, ME, Pred, GetState(Pred)); } // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. if (!(!asLValue && ReceiverReturnsReference(ME))) { - CheckerVisit(ME, Dst, PostVisitSrc, false); + CheckerVisit(ME, Dst, DstEval, false); return; } - + // Handle the case where the message expression returns a reference but // we expect an rvalue. For such cases, convert the reference to - // an rvalue. + // an rvalue. // FIXME: This conversion doesn't actually happen unless the result // of ObjCMessageExpr is consumed by another expression. ExplodedNodeSet DstRValueConvert; - CheckerVisit(ME, DstRValueConvert, PostVisitSrc, false); + CheckerVisit(ME, DstRValueConvert, DstEval, false); QualType LoadTy = ME->getType(); - + static int *ConvertToRvalueTag = 0; for (ExplodedNodeSet::iterator NI = DstRValueConvert.begin(), - NE = DstRValueConvert.end(); - NI!=NE; ++NI) { + NE = DstRValueConvert.end(); NI != NE; ++NI) { const GRState *state = GetState(*NI); EvalLoad(Dst, ME, *NI, state, state->getSVal(ME), &ConvertToRvalueTag, LoadTy); @@ -2173,7 +2180,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // Transfer functions: Miscellaneous statements. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, +void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool asLValue) { ExplodedNodeSet S1; QualType T = CastE->getType(); @@ -2235,8 +2242,8 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, ExplodedNode* N = *I; const GRState* state = GetState(N); SVal V = state->getSVal(Ex); - const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy); - state = Res.getState()->BindExpr(CastE, Res.getSVal()); + V = SVator.EvalCast(V, T, ExTy); + state = state->BindExpr(CastE, V); MakeNode(Dst, CastE, N, state); } return; @@ -2296,7 +2303,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet Tmp2; CheckerVisit(DS, Tmp2, Tmp, true); - + for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) { ExplodedNode *N = *I; const GRState *state = GetState(N); @@ -2311,12 +2318,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, // UnknownVal. if (InitVal.isUnknown() || !getConstraintManager().canReasonAbout(InitVal)) { - InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, + InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Builder->getCurrentBlockCount()); } - + EvalBind(Dst, DS, DS, *I, state, - loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); + loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); } else { state = state->bindDeclWithNoInit(state->getRegion(VD, LC)); @@ -2327,26 +2334,26 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, void GRExprEngine::VisitCondInit(VarDecl *VD, Stmt *S, ExplodedNode *Pred, ExplodedNodeSet& Dst) { - - Expr* InitEx = VD->getInit(); + + Expr* InitEx = VD->getInit(); ExplodedNodeSet Tmp; Visit(InitEx, Pred, Tmp); for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { ExplodedNode *N = *I; const GRState *state = GetState(N); - + const LocationContext *LC = N->getLocationContext(); SVal InitVal = state->getSVal(InitEx); - + // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. if (InitVal.isUnknown() || !getConstraintManager().canReasonAbout(InitVal)) { - InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, + InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Builder->getCurrentBlockCount()); } - + EvalBind(Dst, S, S, N, state, loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); } @@ -2461,12 +2468,14 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, } else if (!T.getTypePtr()->isConstantSizeType()) { // FIXME: Add support for VLAs. + Dst.Add(Pred); return; } else if (T->isObjCInterfaceType()) { // Some code tries to take the sizeof an ObjCInterfaceType, relying that // the compiler has laid out its representation. Just report Unknown // for these. + Dst.Add(Pred); return; } else { @@ -2475,10 +2484,10 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, } } else // Get alignment of the type. - amt = CharUnits::fromQuantity(getContext().getTypeAlign(T) / 8); + amt = getContext().getTypeAlignInChars(T); MakeNode(Dst, Ex, Pred, - GetState(Pred)->BindExpr(Ex, + GetState(Pred)->BindExpr(Ex, ValMgr.makeIntVal(amt.getQuantity(), Ex->getType()))); } @@ -2567,7 +2576,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, assert(IV.getBitWidth() == getContext().getTypeSize(U->getType())); assert(U->getType()->isIntegerType()); assert(IV.isSigned() == U->getType()->isSignedIntegerType()); - SVal X = ValMgr.makeIntVal(IV); + SVal X = ValMgr.makeIntVal(IV); MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X)); return; } @@ -2715,7 +2724,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, if (V2_untested.isUnknownOrUndef()) { MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested)); continue; - } + } DefinedSVal V2 = cast<DefinedSVal>(V2_untested); // Handle all other values. @@ -2770,19 +2779,19 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, } -void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, +void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet & Dst) { // Get the this object region from StoreManager. const MemRegion *R = ValMgr.getRegionManager().getCXXThisRegion(TE->getType(), Pred->getLocationContext()); - + const GRState *state = GetState(Pred); SVal V = state->getSVal(loc::MemRegionVal(R)); MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); } -void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, +void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); } @@ -2808,7 +2817,7 @@ void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A, void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, AsmStmt::inputs_iterator I, AsmStmt::inputs_iterator E, - ExplodedNode* Pred, + ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (I == E) { @@ -2846,7 +2855,7 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - + ExplodedNodeSet Src; if (Expr *RetE = RS->getRetValue()) { Visit(RetE, Pred, Src); @@ -2854,25 +2863,25 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, else { Src.Add(Pred); } - + ExplodedNodeSet CheckedSet; CheckerVisit(RS, CheckedSet, Src, true); - + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) { assert(Builder && "GRStmtNodeBuilder must be defined."); - + Pred = *I; unsigned size = Dst.size(); - + SaveAndRestore<bool> OldSink(Builder->BuildSinks); SaveOr OldHasGen(Builder->HasGeneratedNode); - + getTF().EvalReturn(Dst, *this, *Builder, RS, Pred); - - // Handle the case where no nodes where generated. - if (!Builder->BuildSinks && Dst.size() == size && + + // Handle the case where no nodes where generated. + if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) MakeNode(Dst, RS, Pred, GetState(Pred)); } @@ -2926,7 +2935,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // EXPERIMENTAL: "Conjured" symbols. // FIXME: Handle structs. QualType T = RHS->getType(); - + if ((RightV.isUnknown()||!getConstraintManager().canReasonAbout(RightV)) && (Loc::IsLocType(T) || (T->isScalarType()&&T->isIntegerType()))) { unsigned Count = Builder->getCurrentBlockCount(); @@ -2940,12 +2949,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV); continue; } - + if (!B->isAssignmentOp()) { // Process non-assignments except commas or short-circuited // logical expressions (LAnd and LOr). SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType()); - + if (Result.isUnknown()) { if (OldSt != state) { // Generate a new node if we have already created a new state. @@ -2953,12 +2962,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, } else Tmp3.Add(*I2); - + continue; } - + state = state->BindExpr(B, Result); - + MakeNode(Tmp3, B, *I2, state); continue; } @@ -3004,13 +3013,11 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, QualType RTy = getContext().getCanonicalType(RHS->getType()); // Promote LHS. - llvm::tie(state, V) = SVator.EvalCast(V, state, CLHSTy, LTy); + V = SVator.EvalCast(V, CLHSTy, LTy); // Compute the result of the operation. - SVal Result; - llvm::tie(state, Result) = SVator.EvalCast(EvalBinOp(state, Op, V, - RightV, CTy), - state, B->getType(), CTy); + SVal Result = SVator.EvalCast(EvalBinOp(state, Op, V, RightV, CTy), + B->getType(), CTy); // EXPERIMENTAL: "Conjured" symbols. // FIXME: Handle structs. @@ -3030,12 +3037,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, LHSVal = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count); // However, we need to convert the symbol to the computation type. - llvm::tie(state, Result) = SVator.EvalCast(LHSVal, state, CTy, LTy); + Result = SVator.EvalCast(LHSVal, CTy, LTy); } else { // The left-hand side may bind to a different value then the // computation type. - llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy); + LHSVal = SVator.EvalCast(Result, LTy, CTy); } EvalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result), @@ -3047,24 +3054,24 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, CheckerVisit(B, Dst, Tmp3, false); } -void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, +void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { const GRState *state = GetState(*I); - + // Bind the temporary object to the value of the expression. Then bind // the expression to the location of the object. SVal V = state->getSVal(Ex); - const MemRegion *R = + const MemRegion *R = ValMgr.getRegionManager().getCXXObjectRegion(Ex, Pred->getLocationContext()); state = state->bindLoc(loc::MemRegionVal(R), V); MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); - } + } } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Checker/GRExprEngineExperimentalChecks.cpp index 33479b0cb7e5..89b4e4b6392f 100644 --- a/lib/Analysis/GRExprEngineExperimentalChecks.cpp +++ b/lib/Checker/GRExprEngineExperimentalChecks.cpp @@ -14,7 +14,7 @@ #include "GRExprEngineInternalChecks.h" #include "GRExprEngineExperimentalChecks.h" -#include "clang/Analysis/LocalCheckers.h" +#include "clang/Checker/Checkers/LocalCheckers.h" using namespace clang; diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.h b/lib/Checker/GRExprEngineExperimentalChecks.h index 9a9da32e556e..9a9da32e556e 100644 --- a/lib/Analysis/GRExprEngineExperimentalChecks.h +++ b/lib/Checker/GRExprEngineExperimentalChecks.h diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h index e2354ed09888..64a930d504cf 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.h +++ b/lib/Checker/GRExprEngineInternalChecks.h @@ -19,6 +19,7 @@ namespace clang { class GRExprEngine; +void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng); void RegisterAttrNonNullChecker(GRExprEngine &Eng); void RegisterDereferenceChecker(GRExprEngine &Eng); void RegisterDivZeroChecker(GRExprEngine &Eng); @@ -35,8 +36,8 @@ void RegisterArrayBoundChecker(GRExprEngine &Eng); void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); void RegisterUndefBranchChecker(GRExprEngine &Eng); +void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng); void RegisterUndefResultChecker(GRExprEngine &Eng); - void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); void RegisterOSAtomicChecker(GRExprEngine &Eng); diff --git a/lib/Analysis/GRState.cpp b/lib/Checker/GRState.cpp index 051d465f41b7..592f930316e1 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Checker/GRState.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/GRStateTrait.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/GRTransferFuncs.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" @@ -50,7 +50,8 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, state, RegionRoots); // Clean up the store. - StoreMgr->RemoveDeadBindings(NewState, Loc, SymReaper, RegionRoots); + NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, SymReaper, + RegionRoots); return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState), SymReaper); @@ -301,7 +302,8 @@ bool ScanReachableSymbols::scan(const MemRegion *R) { // Now look at the subregions. if (!SRM.get()) - SRM.reset(state->getStateManager().getStoreManager().getSubRegionMap(state)); + SRM.reset(state->getStateManager().getStoreManager(). + getSubRegionMap(state->getStore())); return SRM->iterSubRegions(R, *this); } diff --git a/lib/Checker/LLVMConventionsChecker.cpp b/lib/Checker/LLVMConventionsChecker.cpp new file mode 100644 index 000000000000..14f0fc1280df --- /dev/null +++ b/lib/Checker/LLVMConventionsChecker.cpp @@ -0,0 +1,335 @@ +//=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines LLVMConventionsChecker, a bunch of small little checks +// for checking specific coding conventions in the LLVM/Clang codebase. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Checker/Checkers/LocalCheckers.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include <string> +#include "llvm/ADT/StringRef.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Generic type checking routines. +//===----------------------------------------------------------------------===// + +static bool IsLLVMStringRef(QualType T) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + + return llvm::StringRef(QualType(RT, 0).getAsString()) == + "class llvm::StringRef"; +} + +static bool InStdNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext(); + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext()); + if (!ND) + return false; + const IdentifierInfo *II = ND->getIdentifier(); + if (!II || II->getName() != "std") + return false; + DC = ND->getDeclContext(); + return isa<TranslationUnitDecl>(DC); +} + +static bool IsStdString(QualType T) { + if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>()) + T = QT->getNamedType(); + + const TypedefType *TT = T->getAs<TypedefType>(); + if (!TT) + return false; + + const TypedefDecl *TD = TT->getDecl(); + + if (!InStdNamespace(TD)) + return false; + + return TD->getName() == "string"; +} + +static bool InClangNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext(); + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext()); + if (!ND) + return false; + const IdentifierInfo *II = ND->getIdentifier(); + if (!II || II->getName() != "clang") + return false; + DC = ND->getDeclContext(); + return isa<TranslationUnitDecl>(DC); +} + +static bool InLLVMNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext(); + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext()); + if (!ND) + return false; + const IdentifierInfo *II = ND->getIdentifier(); + if (!II || II->getName() != "llvm") + return false; + DC = ND->getDeclContext(); + return isa<TranslationUnitDecl>(DC); +} + +static bool IsClangType(const RecordDecl *RD) { + return RD->getName() == "Type" && InClangNamespace(RD); +} + +static bool IsClangDecl(const RecordDecl *RD) { + return RD->getName() == "Decl" && InClangNamespace(RD); +} + +static bool IsClangStmt(const RecordDecl *RD) { + return RD->getName() == "Stmt" && InClangNamespace(RD); +} + +static bool isClangAttr(const RecordDecl *RD) { + return RD->getName() == "Attr" && InClangNamespace(RD); +} + +static bool IsStdVector(QualType T) { + const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>(); + if (!TS) + return false; + + TemplateName TM = TS->getTemplateName(); + TemplateDecl *TD = TM.getAsTemplateDecl(); + + if (!TD || !InStdNamespace(TD)) + return false; + + return TD->getName() == "vector"; +} + +static bool IsSmallVector(QualType T) { + const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>(); + if (!TS) + return false; + + TemplateName TM = TS->getTemplateName(); + TemplateDecl *TD = TM.getAsTemplateDecl(); + + if (!TD || !InLLVMNamespace(TD)) + return false; + + return TD->getName() == "SmallVector"; +} + +//===----------------------------------------------------------------------===// +// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose +// lifetime is shorter than the StringRef's. +//===----------------------------------------------------------------------===// + +namespace { +class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> { + BugReporter &BR; +public: + StringRefCheckerVisitor(BugReporter &br) : BR(br) {} + void VisitChildren(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ; + I != E; ++I) + if (Stmt *child = *I) + Visit(child); + } + void VisitStmt(Stmt *S) { VisitChildren(S); } + void VisitDeclStmt(DeclStmt *DS); +private: + void VisitVarDecl(VarDecl *VD); + void CheckStringRefBoundtoTemporaryString(VarDecl *VD); +}; +} // end anonymous namespace + +static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) { + StringRefCheckerVisitor walker(BR); + walker.Visit(D->getBody()); +} + +void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) { + VisitChildren(S); + + for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I) + if (VarDecl *VD = dyn_cast<VarDecl>(*I)) + VisitVarDecl(VD); +} + +void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) { + Expr *Init = VD->getInit(); + if (!Init) + return; + + // Pattern match for: + // llvm::StringRef x = call() (where call returns std::string) + if (!IsLLVMStringRef(VD->getType())) + return; + CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init); + if (!Ex1) + return; + CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr()); + if (!Ex2 || Ex2->getNumArgs() != 1) + return; + ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0)); + if (!Ex3) + return; + CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr()); + if (!Ex4 || Ex4->getNumArgs() != 1) + return; + ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0)); + if (!Ex5) + return; + CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr()); + if (!Ex6 || !IsStdString(Ex6->getType())) + return; + + // Okay, badness! Report an error. + const char *desc = "StringRef should not be bound to temporary " + "std::string that it outlives"; + + BR.EmitBasicReport(desc, "LLVM Conventions", desc, + VD->getLocStart(), Init->getSourceRange()); +} + +//===----------------------------------------------------------------------===// +// CHECK: Clang AST nodes should not have fields that can allocate +// memory. +//===----------------------------------------------------------------------===// + +static bool AllocatesMemory(QualType T) { + return IsStdVector(T) || IsStdString(T) || IsSmallVector(T); +} + +// This type checking could be sped up via dynamic programming. +static bool IsPartOfAST(const CXXRecordDecl *R) { + if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || isClangAttr(R)) + return true; + + for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(), + E = R->bases_end(); I!=E; ++I) { + CXXBaseSpecifier BS = *I; + QualType T = BS.getType(); + if (const RecordType *baseT = T->getAs<RecordType>()) { + CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl()); + if (IsPartOfAST(baseD)) + return true; + } + } + + return false; +} + +namespace { +class ASTFieldVisitor { + llvm::SmallVector<FieldDecl*, 10> FieldChain; + CXXRecordDecl *Root; + BugReporter &BR; +public: + ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br) + : Root(root), BR(br) {} + + void Visit(FieldDecl *D); + void ReportError(QualType T); +}; +} // end anonymous namespace + +static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) { + if (!IsPartOfAST(R)) + return; + + for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end(); + I != E; ++I) { + ASTFieldVisitor walker(R, BR); + walker.Visit(*I); + } +} + +void ASTFieldVisitor::Visit(FieldDecl *D) { + FieldChain.push_back(D); + + QualType T = D->getType(); + + if (AllocatesMemory(T)) + ReportError(T); + + if (const RecordType *RT = T->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl()->getDefinition(); + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I) + Visit(*I); + } + + FieldChain.pop_back(); +} + +void ASTFieldVisitor::ReportError(QualType T) { + llvm::SmallString<1024> buf; + llvm::raw_svector_ostream os(buf); + + os << "AST class '" << Root->getName() << "' has a field '" + << FieldChain.front()->getName() << "' that allocates heap memory"; + if (FieldChain.size() > 1) { + os << " via the following chain: "; + bool isFirst = true; + for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(), + E=FieldChain.end(); I!=E; ++I) { + if (!isFirst) + os << '.'; + else + isFirst = false; + os << (*I)->getName(); + } + } + os << " (type " << FieldChain.back()->getType().getAsString() << ")"; + os.flush(); + + // Note that this will fire for every translation unit that uses this + // class. This is suboptimal, but at least scan-build will merge + // duplicate HTML reports. In the future we need a unified way of merging + // duplicate reports across translation units. For C++ classes we cannot + // just report warnings when we see an out-of-line method definition for a + // class, as that heuristic doesn't always work (the complete definition of + // the class may be in the header file, for example). + BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions", + os.str(), FieldChain.front()->getLocStart()); +} + +//===----------------------------------------------------------------------===// +// Entry point for all checks. +//===----------------------------------------------------------------------===// + +static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) { + for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end(); + I!=E ; ++I) { + + Decl *D = *I; + + if (D->getBody()) + CheckStringRefAssignedTemporary(D, BR); + + if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D)) + if (R->isDefinition()) + CheckASTMemory(R, BR); + + if (DeclContext *DC_child = dyn_cast<DeclContext>(D)) + ScanCodeDecls(DC_child, BR); + } +} + +void clang::CheckLLVMConventions(TranslationUnitDecl &TU, + BugReporter &BR) { + ScanCodeDecls(&TU, BR); +} + diff --git a/lib/Checker/Makefile b/lib/Checker/Makefile new file mode 100644 index 000000000000..673d152270ca --- /dev/null +++ b/lib/Checker/Makefile @@ -0,0 +1,21 @@ +##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements analyses built on top of source-level CFGs. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangChecker +BUILD_ARCHIVE = 1 + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp index 28f4db788068..4ff98642e1c2 100644 --- a/lib/Analysis/MallocChecker.cpp +++ b/lib/Checker/MallocChecker.cpp @@ -13,10 +13,10 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineExperimentalChecks.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/GRStateTrait.h" -#include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/PathSensitive/SymbolManager.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; @@ -172,6 +172,11 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, const GRState *state) { SVal ArgVal = state->getSVal(CE->getArg(0)); + + // If ptr is NULL, no operation is preformed. + if (ArgVal.isZeroConstant()) + return state; + SymbolRef Sym = ArgVal.getAsLocSymbol(); assert(Sym); diff --git a/lib/Analysis/ManagerRegistry.cpp b/lib/Checker/ManagerRegistry.cpp index 8943db2a2343..d11a997cc0f6 100644 --- a/lib/Analysis/ManagerRegistry.cpp +++ b/lib/Checker/ManagerRegistry.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/ManagerRegistry.h" +#include "clang/Checker/ManagerRegistry.h" using namespace clang; diff --git a/lib/Analysis/MemRegion.cpp b/lib/Checker/MemRegion.cpp index 87d60d340934..194015a11b11 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Checker/MemRegion.cpp @@ -13,12 +13,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/raw_ostream.h" -#include "clang/Analysis/PathSensitive/MemRegion.h" -#include "clang/Analysis/PathSensitive/ValueManager.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Checker/PathSensitive/MemRegion.h" #include "clang/AST/CharUnits.h" #include "clang/AST/StmtVisitor.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; @@ -682,7 +681,7 @@ const MemRegion *MemRegion::StripCasts() const { static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { if (const RecordType *RT = Ty->getAs<RecordType>()) { const RecordDecl *D = RT->getDecl(); - if (!D->getDefinition(Ctx)) + if (!D->getDefinition()) return false; } @@ -760,7 +759,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() { const VarDecl *VD = *I; const VarRegion *VR = 0; - if (!VD->getAttr<BlocksAttr>()) + if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) VR = MemMgr.getVarRegion(VD, this); else { if (LC) diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp index 2ff04878f7ab..29bac9c384c2 100644 --- a/lib/Analysis/NSAutoreleasePoolChecker.cpp +++ b/lib/Checker/NSAutoreleasePoolChecker.cpp @@ -15,9 +15,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "BasicObjCFoundationChecks.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp index e3cf57fd0c1b..e428e2e83f2a 100644 --- a/lib/Analysis/NSErrorChecker.cpp +++ b/lib/Checker/NSErrorChecker.cpp @@ -15,10 +15,10 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" +#include "clang/Checker/Checkers/LocalCheckers.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/Checkers/DereferenceChecker.h" #include "BasicObjCFoundationChecks.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Checker/NoReturnFunctionChecker.cpp index 5cfd9acd5f56..1455d87665db 100644 --- a/lib/Analysis/NoReturnFunctionChecker.cpp +++ b/lib/Checker/NoReturnFunctionChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Checker/PathSensitive/Checker.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Checker/OSAtomicChecker.cpp index 9d34e9ec5c8b..7f4aeca33178 100644 --- a/lib/Analysis/OSAtomicChecker.cpp +++ b/lib/Checker/OSAtomicChecker.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Checker/PathSensitive/Checker.h" #include "clang/Basic/Builtins.h" #include "llvm/ADT/StringSwitch.h" @@ -153,8 +153,7 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, // Handle implicit value casts. if (const TypedRegion *R = dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { - llvm::tie(state, val) = SVator.EvalCast(val, state,R->getValueType(Ctx), - newValueExpr->getType()); + val = SVator.EvalCast(val,R->getValueType(Ctx),newValueExpr->getType()); } Engine.EvalStore(TmpStore, NULL, const_cast<Expr *>(theValueExpr), N, diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Checker/PathDiagnostic.cpp index 734570a21e64..97500d95785c 100644 --- a/lib/Analysis/PathDiagnostic.cpp +++ b/lib/Checker/PathDiagnostic.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathDiagnostic.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" #include "clang/AST/Expr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Checker/PointerArithChecker.cpp index 370233ce38bd..3d62d0c7b9d7 100644 --- a/lib/Analysis/PointerArithChecker.cpp +++ b/lib/Checker/PointerArithChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" using namespace clang; diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Checker/PointerSubChecker.cpp index c597a2580751..acc848ac8edb 100644 --- a/lib/Analysis/PointerSubChecker.cpp +++ b/lib/Checker/PointerSubChecker.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" using namespace clang; diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Checker/PthreadLockChecker.cpp index e95095c7975e..74e266c3edfc 100644 --- a/lib/Analysis/PthreadLockChecker.cpp +++ b/lib/Checker/PthreadLockChecker.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/GRStateTrait.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" #include "GRExprEngineExperimentalChecks.h" #include "llvm/ADT/ImmutableSet.h" diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Checker/RangeConstraintManager.cpp index 2cf3dfb6d0db..c904c33e08d2 100644 --- a/lib/Analysis/RangeConstraintManager.cpp +++ b/lib/Checker/RangeConstraintManager.cpp @@ -13,10 +13,10 @@ //===----------------------------------------------------------------------===// #include "SimpleConstraintManager.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/GRStateTrait.h" -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "clang/Analysis/ManagerRegistry.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/PathSensitive/GRTransferFuncs.h" +#include "clang/Checker/ManagerRegistry.h" #include "llvm/Support/Debug.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableSet.h" diff --git a/lib/Analysis/RegionStore.cpp b/lib/Checker/RegionStore.cpp index a735ed94578e..f70105af1379 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -14,10 +14,10 @@ // parameters are created lazily. // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/MemRegion.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/GRStateTrait.h" +#include "clang/Checker/PathSensitive/MemRegion.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/Support/Optional.h" #include "clang/Basic/TargetInfo.h" @@ -32,81 +32,55 @@ using namespace clang; #define USE_EXPLICIT_COMPOUND 0 //===----------------------------------------------------------------------===// -// Representation of value bindings. +// Representation of binding keys. //===----------------------------------------------------------------------===// namespace { -class BindingVal { +class BindingKey { public: - enum BindingKind { Direct, Default }; + enum Kind { Direct = 0x0, Default = 0x1 }; private: - SVal Value; - BindingKind Kind; - + llvm ::PointerIntPair<const MemRegion*, 1> P; + uint64_t Offset; + + explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k) + : P(r, (unsigned) k), Offset(offset) { assert(r); } public: - BindingVal(SVal V, BindingKind K) : Value(V), Kind(K) {} - - bool isDefault() const { return Kind == Default; } - - const SVal *getValue() const { return &Value; } - - const SVal *getDirectValue() const { return isDefault() ? 0 : &Value; } - - const SVal *getDefaultValue() const { return isDefault() ? &Value : 0; } - + + bool isDefault() const { return P.getInt() == Default; } + bool isDirect() const { return P.getInt() == Direct; } + + const MemRegion *getRegion() const { return P.getPointer(); } + uint64_t getOffset() const { return Offset; } + void Profile(llvm::FoldingSetNodeID& ID) const { - Value.Profile(ID); - ID.AddInteger(Kind); + ID.AddPointer(P.getOpaqueValue()); + ID.AddInteger(Offset); } - - inline bool operator==(const BindingVal& R) const { - return Value == R.Value && Kind == R.Kind; - } - - inline bool operator!=(const BindingVal& R) const { - return !(*this == R); - } -}; -} - -namespace llvm { -static inline -llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) { - if (V.isDefault()) - os << "(default) "; - else - os << "(direct) "; - os << *V.getValue(); - return os; -} -} // end llvm namespace - -//===----------------------------------------------------------------------===// -// Representation of binding keys. -//===----------------------------------------------------------------------===// - -namespace { - class BindingKey : public std::pair<const MemRegion*, uint64_t> { -public: - explicit BindingKey(const MemRegion *r, uint64_t offset) - : std::pair<const MemRegion*,uint64_t>(r, offset) { assert(r); } - const MemRegion *getRegion() const { return first; } - uint64_t getOffset() const { return second; } + static BindingKey Make(const MemRegion *R, Kind k); - void Profile(llvm::FoldingSetNodeID& ID) const { - ID.AddPointer(getRegion()); - ID.AddInteger(getOffset()); + bool operator<(const BindingKey &X) const { + if (P.getOpaqueValue() < X.P.getOpaqueValue()) + return true; + if (P.getOpaqueValue() > X.P.getOpaqueValue()) + return false; + return Offset < X.Offset; + } + + bool operator==(const BindingKey &X) const { + return P.getOpaqueValue() == X.P.getOpaqueValue() && + Offset == X.Offset; } - - static BindingKey Make(const MemRegion *R); }; } // end anonymous namespace namespace llvm { static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) { - os << '(' << K.getRegion() << ',' << K.getOffset() << ')'; + os << '(' << K.getRegion() << ',' << K.getOffset() + << ',' << (K.isDirect() ? "direct" : "default") + << ')'; return os; } } // end llvm namespace @@ -115,7 +89,7 @@ namespace llvm { // Actual Store type. //===----------------------------------------------------------------------===// -typedef llvm::ImmutableMap<BindingKey, BindingVal> RegionBindings; +typedef llvm::ImmutableMap<BindingKey, SVal> RegionBindings; //===----------------------------------------------------------------------===// // Fine-grained control of RegionStoreManager. @@ -178,9 +152,11 @@ static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) { namespace { class RegionStoreSubRegionMap : public SubRegionMap { - typedef llvm::ImmutableSet<const MemRegion*> SetTy; - typedef llvm::DenseMap<const MemRegion*, SetTy> Map; - SetTy::Factory F; +public: + typedef llvm::ImmutableSet<const MemRegion*> Set; + typedef llvm::DenseMap<const MemRegion*, Set> Map; +private: + Set::Factory F; Map M; public: bool add(const MemRegion* Parent, const MemRegion* SubRegion) { @@ -198,6 +174,11 @@ public: void process(llvm::SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R); ~RegionStoreSubRegionMap() {} + + const Set *getSubRegions(const MemRegion *Parent) const { + Map::const_iterator I = M.find(Parent); + return I == M.end() ? NULL : &I->second; + } bool iterSubRegions(const MemRegion* Parent, Visitor& V) const { Map::const_iterator I = M.find(Parent); @@ -205,30 +186,22 @@ public: if (I == M.end()) return true; - llvm::ImmutableSet<const MemRegion*> S = I->second; - for (llvm::ImmutableSet<const MemRegion*>::iterator SI=S.begin(),SE=S.end(); - SI != SE; ++SI) { + Set S = I->second; + for (Set::iterator SI=S.begin(),SE=S.end(); SI != SE; ++SI) { if (!V.Visit(Parent, *SI)) return false; } return true; } - - typedef SetTy::iterator iterator; - - std::pair<iterator, iterator> begin_end(const MemRegion *R) { - Map::iterator I = M.find(R); - SetTy S = I == M.end() ? F.GetEmptySet() : I->second; - return std::make_pair(S.begin(), S.end()); - } }; + class RegionStoreManager : public StoreManager { const RegionStoreFeatures Features; RegionBindings::Factory RBFactory; - typedef llvm::DenseMap<const GRState *, RegionStoreSubRegionMap*> SMCache; + typedef llvm::DenseMap<Store, RegionStoreSubRegionMap*> SMCache; SMCache SC; public: @@ -242,7 +215,9 @@ public: delete (*I).second; } - SubRegionMap *getSubRegionMap(const GRState *state); + SubRegionMap *getSubRegionMap(Store store) { + return getRegionStoreSubRegionMap(store); + } RegionStoreSubRegionMap *getRegionStoreSubRegionMap(Store store); @@ -255,35 +230,7 @@ public: /// setImplicitDefaultValue - Set the default binding for the provided /// MemRegion to the value implicitly defined for compound literals when /// the value is not specified. - const GRState *setImplicitDefaultValue(const GRState *state, - const MemRegion *R, - QualType T); - - /// getLValueString - Returns an SVal representing the lvalue of a - /// StringLiteral. Within RegionStore a StringLiteral has an - /// associated StringRegion, and the lvalue of a StringLiteral is - /// the lvalue of that region. - SVal getLValueString(const StringLiteral* S); - - /// getLValueCompoundLiteral - Returns an SVal representing the - /// lvalue of a compound literal. Within RegionStore a compound - /// literal has an associated region, and the lvalue of the - /// compound literal is the lvalue of that region. - SVal getLValueCompoundLiteral(const CompoundLiteralExpr*); - - /// getLValueVar - Returns an SVal that represents the lvalue of a - /// variable. Within RegionStore a variable has an associated - /// VarRegion, and the lvalue of the variable is the lvalue of that region. - SVal getLValueVar(const VarDecl *VD, const LocationContext *LC); - - SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base); - - SVal getLValueField(const FieldDecl* D, SVal Base); - - SVal getLValueFieldOrIvar(const Decl* D, SVal Base); - - SVal getLValueElement(QualType elementType, SVal Offset, SVal Base); - + Store setImplicitDefaultValue(Store store, const MemRegion *R, QualType T); /// ArrayToPointer - Emulates the "decay" of an array to a pointer /// type. 'Array' represents the lvalue of the array being decayed @@ -293,8 +240,7 @@ public: /// casts from arrays to pointers. SVal ArrayToPointer(Loc Array); - SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L, - NonLoc R, QualType resultTy); + SVal EvalBinOp(BinaryOperator::Opcode Op,Loc L, NonLoc R, QualType resultTy); Store getInitialStore(const LocationContext *InitLoc) { return RBFactory.GetEmptyMap().getRoot(); @@ -304,52 +250,57 @@ public: // Binding values to regions. //===-------------------------------------------------------------------===// - const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, - const Expr *E, unsigned Count, - InvalidatedSymbols *IS) { - return RegionStoreManager::InvalidateRegions(state, &R, &R+1, E, Count, IS); + Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E, + unsigned Count, InvalidatedSymbols *IS) { + return RegionStoreManager::InvalidateRegions(store, &R, &R+1, E, Count, IS); } - const GRState *InvalidateRegions(const GRState *state, - const MemRegion * const *Begin, - const MemRegion * const *End, - const Expr *E, unsigned Count, - InvalidatedSymbols *IS); + Store InvalidateRegions(Store store, + const MemRegion * const *Begin, + const MemRegion * const *End, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS); -private: +public: // Made public for helper classes. + void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R, RegionStoreSubRegionMap &M); - RegionBindings Add(RegionBindings B, BindingKey K, BindingVal V); - RegionBindings Add(RegionBindings B, const MemRegion *R, BindingVal V); + RegionBindings Add(RegionBindings B, BindingKey K, SVal V); + + RegionBindings Add(RegionBindings B, const MemRegion *R, + BindingKey::Kind k, SVal V); - const BindingVal *Lookup(RegionBindings B, BindingKey K); - const BindingVal *Lookup(RegionBindings B, const MemRegion *R); + const SVal *Lookup(RegionBindings B, BindingKey K); + const SVal *Lookup(RegionBindings B, const MemRegion *R, BindingKey::Kind k); RegionBindings Remove(RegionBindings B, BindingKey K); - RegionBindings Remove(RegionBindings B, const MemRegion *R); + RegionBindings Remove(RegionBindings B, const MemRegion *R, + BindingKey::Kind k); + + RegionBindings Remove(RegionBindings B, const MemRegion *R) { + return Remove(Remove(B, R, BindingKey::Direct), R, BindingKey::Default); + } + Store Remove(Store store, BindingKey K); -public: - const GRState *Bind(const GRState *state, Loc LV, SVal V); +public: // Part of public interface to class. - const GRState *BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* CL, - const LocationContext *LC, - SVal V); + Store Bind(Store store, Loc LV, SVal V); - const GRState *BindDecl(const GRState *ST, const VarRegion *VR, - SVal InitVal); + Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL, + const LocationContext *LC, SVal V); - const GRState *BindDeclWithNoInit(const GRState *state, - const VarRegion *) { - return state; + Store BindDecl(Store store, const VarRegion *VR, SVal InitVal); + + Store BindDeclWithNoInit(Store store, const VarRegion *) { + return store; } /// BindStruct - Bind a compound value to a structure. - const GRState *BindStruct(const GRState *, const TypedRegion* R, SVal V); + Store BindStruct(Store store, const TypedRegion* R, SVal V); - const GRState *BindArray(const GRState *state, const TypedRegion* R, SVal V); + Store BindArray(Store store, const TypedRegion* R, SVal V); /// KillStruct - Set the entire struct to unknown. Store KillStruct(Store store, const TypedRegion* R); @@ -372,20 +323,19 @@ public: /// return undefined /// else /// return symbolic - SValuator::CastResult Retrieve(const GRState *state, Loc L, - QualType T = QualType()); + SVal Retrieve(Store store, Loc L, QualType T = QualType()); - SVal RetrieveElement(const GRState *state, const ElementRegion *R); + SVal RetrieveElement(Store store, const ElementRegion *R); - SVal RetrieveField(const GRState *state, const FieldRegion *R); + SVal RetrieveField(Store store, const FieldRegion *R); - SVal RetrieveObjCIvar(const GRState *state, const ObjCIvarRegion *R); + SVal RetrieveObjCIvar(Store store, const ObjCIvarRegion *R); - SVal RetrieveVar(const GRState *state, const VarRegion *R); + SVal RetrieveVar(Store store, const VarRegion *R); - SVal RetrieveLazySymbol(const GRState *state, const TypedRegion *R); + SVal RetrieveLazySymbol(const TypedRegion *R); - SVal RetrieveFieldOrElementCommon(const GRState *state, const TypedRegion *R, + SVal RetrieveFieldOrElementCommon(Store store, const TypedRegion *R, QualType Ty, const MemRegion *superR); /// Retrieve the values in a struct and return a CompoundVal, used when doing @@ -393,20 +343,18 @@ public: /// struct s x, y; /// x = y; /// y's value is retrieved by this method. - SVal RetrieveStruct(const GRState *St, const TypedRegion* R); + SVal RetrieveStruct(Store store, const TypedRegion* R); - SVal RetrieveArray(const GRState *St, const TypedRegion* R); + SVal RetrieveArray(Store store, const TypedRegion* R); /// Get the state and region whose binding this region R corresponds to. - std::pair<const GRState*, const MemRegion*> + std::pair<Store, const MemRegion*> GetLazyBinding(RegionBindings B, const MemRegion *R); - const GRState* CopyLazyBindings(nonloc::LazyCompoundVal V, - const GRState *state, - const TypedRegion *R); + Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store, + const TypedRegion *R); - const ElementRegion *GetElementZeroRegion(const SymbolicRegion *SR, - QualType T); + const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); //===------------------------------------------------------------------===// // State pruning. @@ -414,7 +362,7 @@ public: /// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values. /// It returns a new Store with these values removed. - void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper, + Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); const GRState *EnterStackFrame(const GRState *state, @@ -500,10 +448,6 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) { return M; } -SubRegionMap *RegionStoreManager::getSubRegionMap(const GRState *state) { - return getRegionStoreSubRegionMap(state->getStore()); -} - //===----------------------------------------------------------------------===// // Binding invalidation. //===----------------------------------------------------------------------===// @@ -511,258 +455,227 @@ SubRegionMap *RegionStoreManager::getSubRegionMap(const GRState *state) { void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R, RegionStoreSubRegionMap &M) { - RegionStoreSubRegionMap::iterator I, E; - - for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I) - RemoveSubRegionBindings(B, *I, M); + + if (const RegionStoreSubRegionMap::Set *S = M.getSubRegions(R)) + for (RegionStoreSubRegionMap::Set::iterator I = S->begin(), E = S->end(); + I != E; ++I) + RemoveSubRegionBindings(B, *I, M); B = Remove(B, R); } -const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, - const MemRegion * const *I, - const MemRegion * const *E, - const Expr *Ex, - unsigned Count, - InvalidatedSymbols *IS) { - ASTContext& Ctx = StateMgr.getContext(); - - // Get the mapping of regions -> subregions. - llvm::OwningPtr<RegionStoreSubRegionMap> - SubRegions(getRegionStoreSubRegionMap(state->getStore())); +namespace { +class InvalidateRegionsWorker { + typedef BumpVector<BindingKey> RegionCluster; + typedef llvm::DenseMap<const MemRegion *, RegionCluster *> ClusterMap; + typedef llvm::SmallVector<std::pair<const MemRegion *,RegionCluster*>, 10> + WorkList; + + BumpVectorContext BVC; + ClusterMap ClusterM; + WorkList WL; - RegionBindings B = GetRegionBindings(state->getStore()); - - llvm::DenseMap<const MemRegion *, unsigned> Visited; - llvm::SmallVector<const MemRegion *, 10> WorkList; + RegionStoreManager &RM; + StoreManager::InvalidatedSymbols *IS; + ASTContext &Ctx; + ValueManager &ValMgr; - for ( ; I != E; ++I) { - // Strip away casts. - WorkList.push_back((*I)->StripCasts()); +public: + InvalidateRegionsWorker(RegionStoreManager &rm, + StoreManager::InvalidatedSymbols *is, + ASTContext &ctx, ValueManager &valMgr) + : RM(rm), IS(is), Ctx(ctx), ValMgr(valMgr) {} + + Store InvalidateRegions(Store store, const MemRegion * const *I, + const MemRegion * const *E, + const Expr *Ex, unsigned Count); + +private: + void AddToWorkList(BindingKey K); + void AddToWorkList(const MemRegion *R); + void AddToCluster(BindingKey K); + RegionCluster **getCluster(const MemRegion *R); + void VisitBinding(SVal V); +}; +} + +void InvalidateRegionsWorker::AddToCluster(BindingKey K) { + const MemRegion *R = K.getRegion(); + const MemRegion *baseR = R->getBaseRegion(); + RegionCluster **CPtr = getCluster(baseR); + assert(*CPtr); + (*CPtr)->push_back(K, BVC); +} + +void InvalidateRegionsWorker::AddToWorkList(BindingKey K) { + AddToWorkList(K.getRegion()); +} + +void InvalidateRegionsWorker::AddToWorkList(const MemRegion *R) { + const MemRegion *baseR = R->getBaseRegion(); + RegionCluster **CPtr = getCluster(baseR); + if (RegionCluster *C = *CPtr) { + WL.push_back(std::make_pair(baseR, C)); + *CPtr = NULL; + } +} + +InvalidateRegionsWorker::RegionCluster ** +InvalidateRegionsWorker::getCluster(const MemRegion *R) { + RegionCluster *&CRef = ClusterM[R]; + if (!CRef) { + void *Mem = BVC.getAllocator().Allocate<RegionCluster>(); + CRef = new (Mem) RegionCluster(BVC, 10); } + return &CRef; +} + +void InvalidateRegionsWorker::VisitBinding(SVal V) { + // A symbol? Mark it touched by the invalidation. + if (IS) + if (SymbolRef Sym = V.getAsSymbol()) + IS->insert(Sym); - while (!WorkList.empty()) { - const MemRegion *R = WorkList.back(); - WorkList.pop_back(); - - // Have we visited this region before? - unsigned &visited = Visited[R]; - if (visited) - continue; - visited = 1; + if (const MemRegion *R = V.getAsRegion()) { + AddToWorkList(R); + return; + } + + // Is it a LazyCompoundVal? All references get invalidated as well. + if (const nonloc::LazyCompoundVal *LCS = + dyn_cast<nonloc::LazyCompoundVal>(&V)) { + + const MemRegion *LazyR = LCS->getRegion(); + RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore()); + + for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){ + const MemRegion *baseR = RI.getKey().getRegion(); + if (cast<SubRegion>(baseR)->isSubRegionOf(LazyR)) + VisitBinding(RI.getData()); + } - // Add subregions to work list. - RegionStoreSubRegionMap::iterator I, E; - for (llvm::tie(I, E) = SubRegions->begin_end(R); I!=E; ++I) - WorkList.push_back(*I); + return; + } +} - // Get the old binding. Is it a region? If so, add it to the worklist. - if (Optional<SVal> V = getDirectBinding(B, R)) { - if (const MemRegion *RV = V->getAsRegion()) - WorkList.push_back(RV); +Store InvalidateRegionsWorker::InvalidateRegions(Store store, + const MemRegion * const *I, + const MemRegion * const *E, + const Expr *Ex, unsigned Count) +{ + RegionBindings B = RegionStoreManager::GetRegionBindings(store); + + // Scan the entire store and make the region clusters. + for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI) { + AddToCluster(RI.getKey()); + if (const MemRegion *R = RI.getData().getAsRegion()) { + // Generate a cluster, but don't add the region to the cluster + // if there aren't any bindings. + getCluster(R->getBaseRegion()); + } + } + + // Add the cluster for I .. E to a worklist. + for ( ; I != E; ++I) + AddToWorkList(*I); + + while (!WL.empty()) { + const MemRegion *baseR; + RegionCluster *C; + llvm::tie(baseR, C) = WL.back(); + WL.pop_back(); + + for (RegionCluster::iterator I = C->begin(), E = C->end(); I != E; ++I) { + BindingKey K = *I; - // A symbol? Mark it touched by the invalidation. - if (IS) { - if (SymbolRef Sym = V->getAsSymbol()) - IS->insert(Sym); - } + // Get the old binding. Is it a region? If so, add it to the worklist. + if (const SVal *V = RM.Lookup(B, K)) + VisitBinding(*V); + + B = RM.Remove(B, K); } + + // Now inspect the base region. - // Symbolic region? Mark that symbol touched by the invalidation. if (IS) { - if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) + // Symbolic region? Mark that symbol touched by the invalidation. + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) IS->insert(SR->getSymbol()); } // BlockDataRegion? If so, invalidate captured variables that are passed // by reference. - if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { + if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) { for (BlockDataRegion::referenced_vars_iterator - I = BR->referenced_vars_begin(), E = BR->referenced_vars_end() ; - I != E; ++I) { - const VarRegion *VR = *I; - if (VR->getDecl()->getAttr<BlocksAttr>()) - WorkList.push_back(VR); + BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ; + BI != BE; ++BI) { + const VarRegion *VR = *BI; + const VarDecl *VD = VR->getDecl(); + if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) + AddToWorkList(VR); } continue; } - - // Handle the region itself. - if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R)) { + + if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. - DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy, + DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, Count); - B = Add(B, R, BindingVal(V, BindingVal::Default)); + B = RM.Add(B, baseR, BindingKey::Default, V); continue; } - - if (!R->isBoundable()) - continue; - - const TypedRegion *TR = cast<TypedRegion>(R); + + if (!baseR->isBoundable()) + continue; + + const TypedRegion *TR = cast<TypedRegion>(baseR); QualType T = TR->getValueType(Ctx); - - if (const RecordType *RT = T->getAsStructureType()) { - const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx); + // Invalidate the binding. + if (const RecordType *RT = T->getAsStructureType()) { + const RecordDecl *RD = RT->getDecl()->getDefinition(); // No record definition. There is nothing we can do. - if (!RD) + if (!RD) { + B = RM.Remove(B, baseR); continue; + } // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. - DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy, + DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, Count); - B = Add(B, R, BindingVal(V, BindingVal::Default)); + B = RM.Add(B, baseR, BindingKey::Default, V); continue; - } - + } + if (const ArrayType *AT = Ctx.getAsArrayType(T)) { // Set the default value of the array to conjured symbol. DefinedOrUnknownSVal V = - ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count); - B = Add(B, R, BindingVal(V, BindingVal::Default)); + ValMgr.getConjuredSymbolVal(baseR, Ex, AT->getElementType(), Count); + B = RM.Add(B, baseR, BindingKey::Default, V); continue; } - - if ((isa<FieldRegion>(R)||isa<ElementRegion>(R)||isa<ObjCIvarRegion>(R)) - && Visited[cast<SubRegion>(R)->getSuperRegion()]) { - // For fields and elements whose super region has also been invalidated, - // only remove the old binding. The super region will get set with a - // default value from which we can lazily derive a new symbolic value. - B = Remove(B, R); - continue; - } - - // Invalidate the binding. - DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count); + + DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, T, Count); assert(SymbolManager::canSymbolicate(T) || V.isUnknown()); - B = Add(B, R, BindingVal(V, BindingVal::Direct)); + B = RM.Add(B, baseR, BindingKey::Direct, V); } // Create a new state with the updated bindings. - return state->makeWithStore(B.getRoot()); -} - -//===----------------------------------------------------------------------===// -// getLValueXXX methods. -//===----------------------------------------------------------------------===// - -/// getLValueString - Returns an SVal representing the lvalue of a -/// StringLiteral. Within RegionStore a StringLiteral has an -/// associated StringRegion, and the lvalue of a StringLiteral is the -/// lvalue of that region. -SVal RegionStoreManager::getLValueString(const StringLiteral* S) { - return loc::MemRegionVal(MRMgr.getStringRegion(S)); -} - -/// getLValueVar - Returns an SVal that represents the lvalue of a -/// variable. Within RegionStore a variable has an associated -/// VarRegion, and the lvalue of the variable is the lvalue of that region. -SVal RegionStoreManager::getLValueVar(const VarDecl *VD, - const LocationContext *LC) { - return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC)); -} - -SVal RegionStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) { - return getLValueFieldOrIvar(D, Base); -} - -SVal RegionStoreManager::getLValueField(const FieldDecl* D, SVal Base) { - return getLValueFieldOrIvar(D, Base); -} - -SVal RegionStoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) { - if (Base.isUnknownOrUndef()) - return Base; - - Loc BaseL = cast<Loc>(Base); - const MemRegion* BaseR = 0; - - switch (BaseL.getSubKind()) { - case loc::MemRegionKind: - BaseR = cast<loc::MemRegionVal>(BaseL).getRegion(); - break; - - case loc::GotoLabelKind: - // These are anormal cases. Flag an undefined value. - return UndefinedVal(); - - case loc::ConcreteIntKind: - // While these seem funny, this can happen through casts. - // FIXME: What we should return is the field offset. For example, - // add the field offset to the integer value. That way funny things - // like this work properly: &(((struct foo *) 0xa)->f) - return Base; - - default: - assert(0 && "Unhandled Base."); - return Base; - } - - // NOTE: We must have this check first because ObjCIvarDecl is a subclass - // of FieldDecl. - if (const ObjCIvarDecl *ID = dyn_cast<ObjCIvarDecl>(D)) - return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR)); - - return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR)); + return B.getRoot(); } -SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset, - SVal Base) { - - // If the base is an unknown or undefined value, just return it back. - // FIXME: For absolute pointer addresses, we just return that value back as - // well, although in reality we should return the offset added to that - // value. - if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base)) - return Base; - - // Only handle integer offsets... for now. - if (!isa<nonloc::ConcreteInt>(Offset)) - return UnknownVal(); - - const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion(); - - // Pointer of any type can be cast and used as array base. - const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion); - - // Convert the offset to the appropriate size and signedness. - Offset = ValMgr.convertToArrayIndex(Offset); - - if (!ElemR) { - // - // If the base region is not an ElementRegion, create one. - // This can happen in the following example: - // - // char *p = __builtin_alloc(10); - // p[1] = 8; - // - // Observe that 'p' binds to an AllocaRegion. - // - return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset, - BaseRegion, getContext())); - } - - SVal BaseIdx = ElemR->getIndex(); - - if (!isa<nonloc::ConcreteInt>(BaseIdx)) - return UnknownVal(); - - const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue(); - const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue(); - assert(BaseIdxI.isSigned()); - - // Compute the new index. - SVal NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI)); - - // Construct the new ElementRegion. - const MemRegion *ArrayR = ElemR->getSuperRegion(); - return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR, - getContext())); +Store RegionStoreManager::InvalidateRegions(Store store, + const MemRegion * const *I, + const MemRegion * const *E, + const Expr *Ex, unsigned Count, + InvalidatedSymbols *IS) { + InvalidateRegionsWorker W(*this, IS, getContext(), + StateMgr.getValueManager()); + return W.InvalidateRegions(store, I, E, Ex, Count); } - + //===----------------------------------------------------------------------===// // Extents for regions. //===----------------------------------------------------------------------===// @@ -885,8 +798,7 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) { // Pointer arithmetic. //===----------------------------------------------------------------------===// -SVal RegionStoreManager::EvalBinOp(const GRState *state, - BinaryOperator::Opcode Op, Loc L, NonLoc R, +SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R, QualType resultTy) { // Assume the base location is MemRegionVal. if (!isa<loc::MemRegionVal>(L)) @@ -989,33 +901,33 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, //===----------------------------------------------------------------------===// Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B, - const MemRegion *R) { - if (const BindingVal *BV = Lookup(B, R)) - return Optional<SVal>::create(BV->getDirectValue()); - + const MemRegion *R) { + if (const SVal *V = Lookup(B, R, BindingKey::Direct)) + return *V; + return Optional<SVal>(); } Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B, const MemRegion *R) { - if (R->isBoundable()) if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) if (TR->getValueType(getContext())->isUnionType()) return UnknownVal(); - if (const BindingVal *V = Lookup(B, R)) - return Optional<SVal>::create(V->getDefaultValue()); + if (const SVal *V = Lookup(B, R, BindingKey::Default)) + return *V; return Optional<SVal>(); } Optional<SVal> RegionStoreManager::getBinding(RegionBindings B, const MemRegion *R) { - if (const BindingVal *BV = Lookup(B, R)) - return Optional<SVal>::create(BV->getValue()); - - return Optional<SVal>(); + + if (Optional<SVal> V = getDirectBinding(B, R)) + return V; + + return getDefaultBinding(B, R); } static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) { @@ -1042,42 +954,29 @@ static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) { } const ElementRegion * -RegionStoreManager::GetElementZeroRegion(const SymbolicRegion *SR, QualType T) { +RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) { ASTContext &Ctx = getContext(); SVal idx = ValMgr.makeZeroArrayIndex(); assert(!T.isNull()); - return MRMgr.getElementRegion(T, idx, SR, Ctx); + return MRMgr.getElementRegion(T, idx, R, Ctx); } - - - -SValuator::CastResult -RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { +SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { assert(!isa<UnknownVal>(L) && "location unknown"); assert(!isa<UndefinedVal>(L) && "location undefined"); // FIXME: Is this even possible? Shouldn't this be treated as a null // dereference at a higher level? if (isa<loc::ConcreteInt>(L)) - return SValuator::CastResult(state, UndefinedVal()); + return UndefinedVal(); const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion(); - // FIXME: return symbolic value for these cases. - // Example: - // void f(int* p) { int x = *p; } - // char* p = alloca(); - // read(p); - // c = *p; - if (isa<AllocaRegion>(MR)) - return SValuator::CastResult(state, UnknownVal()); - - if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) - MR = GetElementZeroRegion(SR, T); + if (isa<AllocaRegion>(MR) || isa<SymbolicRegion>(MR)) + MR = GetElementZeroRegion(MR, T); if (isa<CodeTextRegion>(MR)) - return SValuator::CastResult(state, UnknownVal()); + return UnknownVal(); // FIXME: Perhaps this method should just take a 'const MemRegion*' argument // instead of 'Loc', and have the other Loc cases handled at a higher level. @@ -1105,23 +1004,21 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { #endif if (RTy->isStructureType()) - return SValuator::CastResult(state, RetrieveStruct(state, R)); + return RetrieveStruct(store, R); // FIXME: Handle unions. if (RTy->isUnionType()) - return SValuator::CastResult(state, UnknownVal()); + return UnknownVal(); if (RTy->isArrayType()) - return SValuator::CastResult(state, RetrieveArray(state, R)); + return RetrieveArray(store, R); // FIXME: handle Vector types. if (RTy->isVectorType()) - return SValuator::CastResult(state, UnknownVal()); + return UnknownVal(); if (const FieldRegion* FR = dyn_cast<FieldRegion>(R)) - return SValuator::CastResult(state, - CastRetrievedVal(RetrieveField(state, FR), FR, - T, false)); + return CastRetrievedVal(RetrieveField(store, FR), FR, T, false); if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) { // FIXME: Here we actually perform an implicit conversion from the loaded @@ -1129,9 +1026,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // more intelligently. For example, an 'element' can encompass multiple // bound regions (e.g., several bound bytes), or could be a subset of // a larger value. - return SValuator::CastResult(state, - CastRetrievedVal(RetrieveElement(state, ER), - ER, T, false)); + return CastRetrievedVal(RetrieveElement(store, ER), ER, T, false); } if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) { @@ -1141,9 +1036,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // reinterpretted, it is possible we stored a different value that could // fit within the ivar. Either we need to cast these when storing them // or reinterpret them lazily (as we do here). - return SValuator::CastResult(state, - CastRetrievedVal(RetrieveObjCIvar(state, IVR), - IVR, T, false)); + return CastRetrievedVal(RetrieveObjCIvar(store, IVR), IVR, T, false); } if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { @@ -1153,18 +1046,15 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // variable is reinterpretted, it is possible we stored a different value // that could fit within the variable. Either we need to cast these when // storing them or reinterpret them lazily (as we do here). - return SValuator::CastResult(state, - CastRetrievedVal(RetrieveVar(state, VR), VR, T, - false)); + return CastRetrievedVal(RetrieveVar(store, VR), VR, T, false); } - RegionBindings B = GetRegionBindings(state->getStore()); - const BindingVal *V = Lookup(B, R); + RegionBindings B = GetRegionBindings(store); + const SVal *V = Lookup(B, R, BindingKey::Direct); // Check if the region has a binding. if (V) - if (SVal const *SV = V->getValue()) - return SValuator::CastResult(state, *SV); + return *V; // The location does not have a bound value. This means that it has // the value it had upon its creation and/or entry to the analyzed @@ -1174,44 +1064,45 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // upon creation. All heap allocated blocks are considered to // have undefined values as well unless they are explicitly bound // to specific values. - return SValuator::CastResult(state, UndefinedVal()); + return UndefinedVal(); } // All other values are symbolic. - return SValuator::CastResult(state, ValMgr.getRegionValueSymbolVal(R, RTy)); + return ValMgr.getRegionValueSymbolVal(R, RTy); } -std::pair<const GRState*, const MemRegion*> +std::pair<Store, const MemRegion *> RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) { if (Optional<SVal> OV = getDirectBinding(B, R)) if (const nonloc::LazyCompoundVal *V = dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer())) - return std::make_pair(V->getState(), V->getRegion()); + return std::make_pair(V->getStore(), V->getRegion()); if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { - const std::pair<const GRState *, const MemRegion *> &X = + const std::pair<Store, const MemRegion *> &X = GetLazyBinding(B, ER->getSuperRegion()); - if (X.first) + if (X.second) return std::make_pair(X.first, MRMgr.getElementRegionWithSuper(ER, X.second)); } else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) { - const std::pair<const GRState *, const MemRegion *> &X = + const std::pair<Store, const MemRegion *> &X = GetLazyBinding(B, FR->getSuperRegion()); - if (X.first) + if (X.second) return std::make_pair(X.first, MRMgr.getFieldRegionWithSuper(FR, X.second)); } - - return std::make_pair((const GRState*) 0, (const MemRegion *) 0); + // The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is + // possible for a valid lazy binding. + return std::make_pair((Store) 0, (const MemRegion *) 0); } -SVal RegionStoreManager::RetrieveElement(const GRState* state, +SVal RegionStoreManager::RetrieveElement(Store store, const ElementRegion* R) { // Check if the region has a binding. - RegionBindings B = GetRegionBindings(state->getStore()); + RegionBindings B = GetRegionBindings(store); if (Optional<SVal> V = getDirectBinding(B, R)) return *V; @@ -1256,29 +1147,29 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state, dyn_cast<nonloc::LazyCompoundVal>(V)) { R = MRMgr.getElementRegionWithSuper(R, LCV->getRegion()); - return RetrieveElement(LCV->getState(), R); + return RetrieveElement(LCV->getStore(), R); } // Other cases: give up. return UnknownVal(); } - return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR); + return RetrieveFieldOrElementCommon(store, R, R->getElementType(), superR); } -SVal RegionStoreManager::RetrieveField(const GRState* state, +SVal RegionStoreManager::RetrieveField(Store store, const FieldRegion* R) { // Check if the region has a binding. - RegionBindings B = GetRegionBindings(state->getStore()); + RegionBindings B = GetRegionBindings(store); if (Optional<SVal> V = getDirectBinding(B, R)) return *V; QualType Ty = R->getValueType(getContext()); - return RetrieveFieldOrElementCommon(state, R, Ty, R->getSuperRegion()); + return RetrieveFieldOrElementCommon(store, R, Ty, R->getSuperRegion()); } -SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, +SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store, const TypedRegion *R, QualType Ty, const MemRegion *superR) { @@ -1286,7 +1177,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, // At this point we have already checked in either RetrieveElement or // RetrieveField if 'R' has a direct binding. - RegionBindings B = GetRegionBindings(state->getStore()); + RegionBindings B = GetRegionBindings(store); while (superR) { if (const Optional<SVal> &D = getDefaultBinding(B, superR)) { @@ -1313,18 +1204,14 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, } // Lazy binding? - const GRState *lazyBindingState = NULL; + Store lazyBindingStore = NULL; const MemRegion *lazyBindingRegion = NULL; - llvm::tie(lazyBindingState, lazyBindingRegion) = GetLazyBinding(B, R); - - if (lazyBindingState) { - assert(lazyBindingRegion && "Lazy-binding region not set"); - - if (isa<ElementRegion>(R)) - return RetrieveElement(lazyBindingState, - cast<ElementRegion>(lazyBindingRegion)); + llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R); - return RetrieveField(lazyBindingState, + if (lazyBindingRegion) { + if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion)) + return RetrieveElement(lazyBindingStore, ER); + return RetrieveField(lazyBindingStore, cast<FieldRegion>(lazyBindingRegion)); } @@ -1345,11 +1232,10 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, return ValMgr.getRegionValueSymbolVal(R, Ty); } -SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state, - const ObjCIvarRegion* R) { +SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){ // Check if the region has a binding. - RegionBindings B = GetRegionBindings(state->getStore()); + RegionBindings B = GetRegionBindings(store); if (Optional<SVal> V = getDirectBinding(B, R)) return *V; @@ -1365,30 +1251,42 @@ SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state, return UnknownVal(); } - return RetrieveLazySymbol(state, R); + return RetrieveLazySymbol(R); } -SVal RegionStoreManager::RetrieveVar(const GRState *state, - const VarRegion *R) { +SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) { // Check if the region has a binding. - RegionBindings B = GetRegionBindings(state->getStore()); + RegionBindings B = GetRegionBindings(store); if (Optional<SVal> V = getDirectBinding(B, R)) return *V; // Lazily derive a value for the VarRegion. const VarDecl *VD = R->getDecl(); + QualType T = VD->getType(); + const MemSpaceRegion *MS = R->getMemorySpace(); + + if (isa<UnknownSpaceRegion>(MS) || + isa<StackArgumentsSpaceRegion>(MS)) + return ValMgr.getRegionValueSymbolVal(R, T); - if (R->hasGlobalsOrParametersStorage() || - isa<UnknownSpaceRegion>(R->getMemorySpace())) - return ValMgr.getRegionValueSymbolVal(R, VD->getType()); + if (isa<GlobalsSpaceRegion>(MS)) { + if (VD->isFileVarDecl()) + return ValMgr.getRegionValueSymbolVal(R, T); + if (T->isIntegerType()) + return ValMgr.makeIntVal(0, T); + if (T->isPointerType()) + return ValMgr.makeNull(); + + return UnknownVal(); + } + return UndefinedVal(); } -SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state, - const TypedRegion *R) { +SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { QualType valTy = R->getValueType(getContext()); @@ -1396,8 +1294,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state, return ValMgr.getRegionValueSymbolVal(R, valTy); } -SVal RegionStoreManager::RetrieveStruct(const GRState *state, - const TypedRegion* R) { +SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { QualType T = R->getValueType(getContext()); assert(T->isStructureType()); @@ -1417,18 +1314,17 @@ SVal RegionStoreManager::RetrieveStruct(const GRState *state, Field != FieldEnd; ++Field) { FieldRegion* FR = MRMgr.getFieldRegion(*Field, R); QualType FTy = (*Field)->getType(); - SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy).getSVal(); + SVal FieldValue = Retrieve(store, loc::MemRegionVal(FR), FTy).getSVal(); StructVal = getBasicVals().consVals(FieldValue, StructVal); } return ValMgr.makeCompoundVal(T, StructVal); #else - return ValMgr.makeLazyCompoundVal(state, R); + return ValMgr.makeLazyCompoundVal(store, R); #endif } -SVal RegionStoreManager::RetrieveArray(const GRState *state, - const TypedRegion * R) { +SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) { #if USE_EXPLICIT_COMPOUND QualType T = R->getValueType(getContext()); ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr()); @@ -1440,14 +1336,14 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state, ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R, getContext()); QualType ETy = ER->getElementType(); - SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy).getSVal(); + SVal ElementVal = Retrieve(store, loc::MemRegionVal(ER), ETy).getSVal(); ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal); } return ValMgr.makeCompoundVal(T, ArrayVal); #else assert(isa<ConstantArrayType>(R->getValueType(getContext()))); - return ValMgr.makeLazyCompoundVal(state, R); + return ValMgr.makeLazyCompoundVal(store, R); #endif } @@ -1458,14 +1354,14 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state, Store RegionStoreManager::Remove(Store store, Loc L) { if (isa<loc::MemRegionVal>(L)) if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion()) - return Remove(store, BindingKey::Make(R)); + return Remove(GetRegionBindings(store), R).getRoot(); return store; } -const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { +Store RegionStoreManager::Bind(Store store, Loc L, SVal V) { if (isa<loc::ConcreteInt>(L)) - return state; + return store; // If we get here, the location should be a region. const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion(); @@ -1473,7 +1369,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { // Check if the region is a struct region. if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) if (TR->getValueType(getContext())->isStructureType()) - return BindStruct(state, TR, V); + return BindStruct(store, TR, V); // Special case: the current region represents a cast and it and the super // region both have pointer types or intptr_t types. If so, perform the @@ -1490,14 +1386,13 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { if (IsAnyPointerOrIntptr(superTy, Ctx) && IsAnyPointerOrIntptr(erTy, Ctx)) { - SValuator::CastResult cr = - ValMgr.getSValuator().EvalCast(V, state, superTy, erTy); - return Bind(cr.getState(), loc::MemRegionVal(superR), cr.getSVal()); + V = ValMgr.getSValuator().EvalCast(V, superTy, erTy); + return Bind(store, loc::MemRegionVal(superR), V); } // For now, just invalidate the fields of the struct/union/class. // FIXME: Precisely handle the fields of the record. if (superTy->isRecordType()) - return InvalidateRegion(state, superR, NULL, 0, NULL); + return InvalidateRegion(store, superR, NULL, 0, NULL); } } } @@ -1516,39 +1411,35 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { } // Perform the binding. - RegionBindings B = GetRegionBindings(state->getStore()); - return state->makeWithStore(Add(B, R, - BindingVal(V, BindingVal::Direct)).getRoot()); + RegionBindings B = GetRegionBindings(store); + return Add(B, R, BindingKey::Direct, V).getRoot(); } -const GRState *RegionStoreManager::BindDecl(const GRState *ST, - const VarRegion *VR, - SVal InitVal) { +Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR, + SVal InitVal) { QualType T = VR->getDecl()->getType(); if (T->isArrayType()) - return BindArray(ST, VR, InitVal); + return BindArray(store, VR, InitVal); if (T->isStructureType()) - return BindStruct(ST, VR, InitVal); + return BindStruct(store, VR, InitVal); - return Bind(ST, ValMgr.makeLoc(VR), InitVal); + return Bind(store, ValMgr.makeLoc(VR), InitVal); } // FIXME: this method should be merged into Bind(). -const GRState * -RegionStoreManager::BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr *CL, - const LocationContext *LC, - SVal V) { - return Bind(state, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), +Store RegionStoreManager::BindCompoundLiteral(Store store, + const CompoundLiteralExpr *CL, + const LocationContext *LC, + SVal V) { + return Bind(store, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), V); } -const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state, - const MemRegion *R, - QualType T) { - Store store = state->getStore(); +Store RegionStoreManager::setImplicitDefaultValue(Store store, + const MemRegion *R, + QualType T) { RegionBindings B = GetRegionBindings(store); SVal V; @@ -1562,23 +1453,24 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state, V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy); } else { - return state; + return store; } - return state->makeWithStore(Add(B, R, - BindingVal(V, BindingVal::Default)).getRoot()); + return Add(B, R, BindingKey::Default, V).getRoot(); } -const GRState *RegionStoreManager::BindArray(const GRState *state, - const TypedRegion* R, - SVal Init) { - - QualType T = R->getValueType(getContext()); - ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr()); - QualType ElementTy = CAT->getElementType(); - - uint64_t size = CAT->getSize().getZExtValue(); - +Store RegionStoreManager::BindArray(Store store, const TypedRegion* R, + SVal Init) { + + ASTContext &Ctx = getContext(); + const ArrayType *AT = + cast<ArrayType>(Ctx.getCanonicalType(R->getValueType(Ctx))); + QualType ElementTy = AT->getElementType(); + Optional<uint64_t> Size; + + if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(AT)) + Size = CAT->getSize().getZExtValue(); + // Check if the init expr is a StringLiteral. if (isa<loc::MemRegionVal>(Init)) { const MemRegion* InitR = cast<loc::MemRegionVal>(Init).getRegion(); @@ -1590,6 +1482,11 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, // Copy bytes from the string literal into the target array. Trailing bytes // in the array that are not covered by the string literal are initialized // to zero. + + // We assume that string constants are bound to + // constant arrays. + uint64_t size = Size.getValue(); + for (uint64_t i = 0; i < size; ++i, ++j) { if (j >= len) break; @@ -1599,26 +1496,26 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, getContext()); SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true); - state = Bind(state, loc::MemRegionVal(ER), V); + store = Bind(store, loc::MemRegionVal(ER), V); } - return state; + return store; } // Handle lazy compound values. if (nonloc::LazyCompoundVal *LCV = dyn_cast<nonloc::LazyCompoundVal>(&Init)) - return CopyLazyBindings(*LCV, state, R); + return CopyLazyBindings(*LCV, store, R); // Remaining case: explicit compound values. if (Init.isUnknown()) - return setImplicitDefaultValue(state, R, ElementTy); + return setImplicitDefaultValue(store, R, ElementTy); nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init); nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end(); uint64_t i = 0; - for (; i < size; ++i, ++VI) { + for (; Size.hasValue() ? i < Size.getValue() : true ; ++i, ++VI) { // The init list might be shorter than the array length. if (VI == VE) break; @@ -1626,27 +1523,25 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, SVal Idx = ValMgr.makeArrayIndex(i); const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); - if (CAT->getElementType()->isStructureType()) - state = BindStruct(state, ER, *VI); + if (ElementTy->isStructureType()) + store = BindStruct(store, ER, *VI); else - // FIXME: Do we need special handling of nested arrays? - state = Bind(state, ValMgr.makeLoc(ER), *VI); + store = Bind(store, ValMgr.makeLoc(ER), *VI); } // If the init list is shorter than the array length, set the // array default value. - if (i < size) - state = setImplicitDefaultValue(state, R, ElementTy); + if (Size.hasValue() && i < Size.getValue()) + store = setImplicitDefaultValue(store, R, ElementTy); - return state; + return store; } -const GRState * -RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R, - SVal V) { +Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, + SVal V) { if (!Features.supportsFields()) - return state; + return store; QualType T = R->getValueType(getContext()); assert(T->isStructureType()); @@ -1655,16 +1550,16 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R, RecordDecl* RD = RT->getDecl(); if (!RD->isDefinition()) - return state; + return store; // Handle lazy compound values. if (const nonloc::LazyCompoundVal *LCV=dyn_cast<nonloc::LazyCompoundVal>(&V)) - return CopyLazyBindings(*LCV, state, R); + return CopyLazyBindings(*LCV, store, R); // We may get non-CompoundVal accidentally due to imprecise cast logic. // Ignore them and kill the field values. if (V.isUnknown() || !isa<nonloc::CompoundVal>(V)) - return state->makeWithStore(KillStruct(state->getStore(), R)); + return KillStruct(store, R); nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V); nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end(); @@ -1680,22 +1575,21 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R, const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R); if (FTy->isArrayType()) - state = BindArray(state, FR, *VI); + store = BindArray(store, FR, *VI); else if (FTy->isStructureType()) - state = BindStruct(state, FR, *VI); + store = BindStruct(store, FR, *VI); else - state = Bind(state, ValMgr.makeLoc(FR), *VI); + store = Bind(store, ValMgr.makeLoc(FR), *VI); } // There may be fewer values in the initialize list than the fields of struct. if (FI != FE) { - Store store = state->getStore(); RegionBindings B = GetRegionBindings(store); - B = Add(B, R, BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default)); - state = state->makeWithStore(B.getRoot()); + B = Add(B, R, BindingKey::Default, ValMgr.makeIntVal(0, false)); + store = B.getRoot(); } - return state; + return store; } Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) { @@ -1705,74 +1599,70 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) { RemoveSubRegionBindings(B, R, *SubRegions); // Set the default value of the struct region to "unknown". - B = Add(B, R, BindingVal(UnknownVal(), BindingVal::Default)); - - return B.getRoot(); + return Add(B, R, BindingKey::Default, UnknownVal()).getRoot(); } -const GRState* -RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, - const GRState *state, - const TypedRegion *R) { +Store RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, + Store store, const TypedRegion *R) { // Nuke the old bindings stemming from R. - RegionBindings B = GetRegionBindings(state->getStore()); + RegionBindings B = GetRegionBindings(store); llvm::OwningPtr<RegionStoreSubRegionMap> - SubRegions(getRegionStoreSubRegionMap(state->getStore())); + SubRegions(getRegionStoreSubRegionMap(store)); // B and DVM are updated after the call to RemoveSubRegionBindings. RemoveSubRegionBindings(B, R, *SubRegions.get()); // Now copy the bindings. This amounts to just binding 'V' to 'R'. This // results in a zero-copy algorithm. - return state->makeWithStore(Add(B, R, - BindingVal(V, BindingVal::Direct)).getRoot()); + return Add(B, R, BindingKey::Direct, V).getRoot(); } //===----------------------------------------------------------------------===// // "Raw" retrievals and bindings. //===----------------------------------------------------------------------===// -BindingKey BindingKey::Make(const MemRegion *R) { +BindingKey BindingKey::Make(const MemRegion *R, Kind k) { if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { const RegionRawOffset &O = ER->getAsRawOffset(); if (O.getRegion()) - return BindingKey(O.getRegion(), O.getByteOffset()); + return BindingKey(O.getRegion(), O.getByteOffset(), k); // FIXME: There are some ElementRegions for which we cannot compute // raw offsets yet, including regions with symbolic offsets. } - return BindingKey(R, 0); + return BindingKey(R, 0, k); } -RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K, - BindingVal V) { +RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K, SVal V) { return RBFactory.Add(B, K, V); } RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R, - BindingVal V) { - return Add(B, BindingKey::Make(R), V); + BindingKey::Kind k, SVal V) { + return Add(B, BindingKey::Make(R, k), V); } -const BindingVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) { +const SVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) { return B.lookup(K); } -const BindingVal *RegionStoreManager::Lookup(RegionBindings B, - const MemRegion *R) { - return Lookup(B, BindingKey::Make(R)); +const SVal *RegionStoreManager::Lookup(RegionBindings B, + const MemRegion *R, + BindingKey::Kind k) { + return Lookup(B, BindingKey::Make(R, k)); } RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) { return RBFactory.Remove(B, K); } -RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R){ - return Remove(B, BindingKey::Make(R)); +RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R, + BindingKey::Kind k){ + return Remove(B, BindingKey::Make(R, k)); } Store RegionStoreManager::Remove(Store store, BindingKey K) { @@ -1784,13 +1674,12 @@ Store RegionStoreManager::Remove(Store store, BindingKey K) { // State pruning. //===----------------------------------------------------------------------===// -void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, - SymbolReaper& SymReaper, +Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) { - typedef std::pair<const GRState*, const MemRegion *> RBDNode; + typedef std::pair<Store, const MemRegion *> RBDNode; - Store store = state.getStore(); RegionBindings B = GetRegionBindings(store); // The backmap from regions to subregions. @@ -1825,7 +1714,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, if (const VarRegion* VR = dyn_cast<VarRegion>(R)) { if (SymReaper.isLive(Loc, VR)) - WorkList.push_back(std::make_pair(&state, VR)); + WorkList.push_back(std::make_pair(store, VR)); continue; } @@ -1833,7 +1722,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, llvm::SmallVectorImpl<RBDNode> &Q = SymReaper.isLive(SR->getSymbol()) ? WorkList : Postponed; - Q.push_back(std::make_pair(&state, SR)); + Q.push_back(std::make_pair(store, SR)); continue; } @@ -1847,7 +1736,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Enqueue the RegionRoots onto WorkList. for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(), E=RegionRoots.end(); I!=E; ++I) { - WorkList.push_back(std::make_pair(&state, *I)); + WorkList.push_back(std::make_pair(store, *I)); } RegionRoots.clear(); @@ -1864,23 +1753,24 @@ tryAgain: Visited.insert(N); const MemRegion *R = N.second; - const GRState *state_N = N.first; + Store store_N = N.first; // Enqueue subregions. RegionStoreSubRegionMap *M; - if (&state == state_N) + if (store == store_N) M = SubRegions.get(); else { - RegionStoreSubRegionMap *& SM = SC[state_N]; + RegionStoreSubRegionMap *& SM = SC[store_N]; if (!SM) - SM = getRegionStoreSubRegionMap(state_N->getStore()); + SM = getRegionStoreSubRegionMap(store_N); M = SM; } - - RegionStoreSubRegionMap::iterator I, E; - for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I) - WorkList.push_back(std::make_pair(state_N, *I)); + + if (const RegionStoreSubRegionMap::Set *S = M->getSubRegions(R)) + for (RegionStoreSubRegionMap::Set::iterator I = S->begin(), E = S->end(); + I != E; ++I) + WorkList.push_back(std::make_pair(store_N, *I)); // Enqueue the super region. if (const SubRegion *SR = dyn_cast<SubRegion>(R)) { @@ -1891,7 +1781,7 @@ tryAgain: // pointer arithmetic can get us to the other fields or elements. assert(isa<FieldRegion>(R) || isa<ElementRegion>(R) || isa<ObjCIvarRegion>(R)); - WorkList.push_back(std::make_pair(state_N, superR)); + WorkList.push_back(std::make_pair(store_N, superR)); } } @@ -1908,14 +1798,13 @@ tryAgain: RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end(); RI != RE; ++RI) { if ((*RI)->getDecl()->getAttr<BlocksAttr>()) - WorkList.push_back(std::make_pair(state_N, *RI)); + WorkList.push_back(std::make_pair(store_N, *RI)); } // No possible data bindings on a BlockDataRegion. Continue to the // next region in the worklist. continue; } - Store store_N = state_N->getStore(); RegionBindings B_N = GetRegionBindings(store_N); // Get the data binding for R (if any). @@ -1927,7 +1816,7 @@ tryAgain: dyn_cast<nonloc::LazyCompoundVal>(V.getPointer())) { const LazyCompoundValData *D = LCV->getCVData(); - WorkList.push_back(std::make_pair(D->getState(), D->getRegion())); + WorkList.push_back(std::make_pair(D->getStore(), D->getRegion())); } else { // Update the set of live symbols. @@ -1937,7 +1826,7 @@ tryAgain: // If V is a region, then add it to the worklist. if (const MemRegion *RX = V->getAsRegion()) - WorkList.push_back(std::make_pair(state_N, RX)); + WorkList.push_back(std::make_pair(store_N, RX)); } } } @@ -1960,27 +1849,27 @@ tryAgain: // We have now scanned the store, marking reachable regions and symbols // as live. We now remove all the regions that are dead from the store // as well as update DSymbols with the set symbols that are now dead. + Store new_store = store; for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { const MemRegion* R = I.getKey().getRegion(); // If this region live? Is so, none of its symbols are dead. - if (Visited.count(std::make_pair(&state, R))) + if (Visited.count(std::make_pair(store, R))) continue; // Remove this dead region from the store. - store = Remove(store, I.getKey()); + new_store = Remove(new_store, I.getKey()); // Mark all non-live symbols that this region references as dead. if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R)) SymReaper.maybeDead(SymR->getSymbol()); - SVal X = *I.getData().getValue(); + SVal X = I.getData(); SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); for (; SI != SE; ++SI) SymReaper.maybeDead(*SI); } - // Write the store back. - state.setStore(store); + return new_store; } GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, @@ -1993,12 +1882,13 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end(); // Copy the arg expression value to the arg variables. + Store store = state->getStore(); for (; AI != AE; ++AI, ++PI) { SVal ArgVal = state->getSVal(*AI); - state = Bind(state, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal); + store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal); } - return state; + return state->makeWithStore(store); } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Checker/ReturnPointerRangeChecker.cpp index b0350cb576ff..949ded507c5b 100644 --- a/lib/Analysis/ReturnPointerRangeChecker.cpp +++ b/lib/Checker/ReturnPointerRangeChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/ReturnStackAddressChecker.cpp b/lib/Checker/ReturnStackAddressChecker.cpp new file mode 100644 index 000000000000..9cbabba4a5f5 --- /dev/null +++ b/lib/Checker/ReturnStackAddressChecker.cpp @@ -0,0 +1,125 @@ +//== ReturnStackAddressChecker.cpp ------------------------------*- 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 ReturnStackAddressChecker, which is a path-sensitive +// check which looks for the addresses of stack variables being returned to +// callers. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.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" + +using namespace clang; + +namespace { +class ReturnStackAddressChecker : + public CheckerVisitor<ReturnStackAddressChecker> { + BuiltinBug *BT; +public: + ReturnStackAddressChecker() : BT(0) {} + static void *getTag(); + void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS); +private: + void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE); +}; +} + +void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) { + Eng.registerCheck(new ReturnStackAddressChecker()); +} + +void *ReturnStackAddressChecker::getTag() { + static int x = 0; return &x; +} + +void ReturnStackAddressChecker::EmitStackError(CheckerContext &C, + const MemRegion *R, + const Expr *RetE) { + ExplodedNode *N = C.GenerateSink(); + + if (!N) + return; + + if (!BT) + BT = new BuiltinBug("Return of address to stack-allocated memory"); + + // Generate a report for this bug. + llvm::SmallString<512> buf; + llvm::raw_svector_ostream os(buf); + SourceRange range; + + // Get the base region, stripping away fields and elements. + R = R->getBaseRegion(); + + // Check if the region is a compound literal. + if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { + const CompoundLiteralExpr* CL = CR->getLiteralExpr(); + os << "Address of stack memory associated with a compound literal " + "declared on line " + << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart()) + << " returned to caller"; + range = CL->getSourceRange(); + } + else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) { + const Expr* ARE = AR->getExpr(); + SourceLocation L = ARE->getLocStart(); + range = ARE->getSourceRange(); + os << "Address of stack memory allocated by call to alloca() on line " + << C.getSourceManager().getInstantiationLineNumber(L) + << " returned to caller"; + } + else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { + const BlockDecl *BD = BR->getCodeRegion()->getDecl(); + SourceLocation L = BD->getLocStart(); + range = BD->getSourceRange(); + os << "Address of stack-allocated block declared on line " + << C.getSourceManager().getInstantiationLineNumber(L) + << " returned to caller"; + } + else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { + os << "Address of stack memory associated with local variable '" + << VR->getString() << "' returned"; + range = VR->getDecl()->getSourceRange(); + } + else { + assert(false && "Invalid region in ReturnStackAddressChecker."); + return; + } + + RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); + report->addRange(RetE->getSourceRange()); + if (range.isValid()) + report->addRange(range); + + C.EmitReport(report); +} + +void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, + const ReturnStmt *RS) { + + const Expr *RetE = RS->getRetValue(); + if (!RetE) + return; + + SVal V = C.getState()->getSVal(RetE); + const MemRegion *R = V.getAsRegion(); + + if (!R || !R->hasStackStorage()) + return; + + if (R->hasStackStorage()) { + EmitStackError(C, R, RetE); + return; + } +} diff --git a/lib/Analysis/ReturnUndefChecker.cpp b/lib/Checker/ReturnUndefChecker.cpp index 7cd71265805b..ee259883e48c 100644 --- a/lib/Analysis/ReturnUndefChecker.cpp +++ b/lib/Checker/ReturnUndefChecker.cpp @@ -14,9 +14,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "llvm/ADT/SmallString.h" using namespace clang; diff --git a/lib/Analysis/SVals.cpp b/lib/Checker/SVals.cpp index fbdb73b0ef2e..28b3fce050bb 100644 --- a/lib/Analysis/SVals.cpp +++ b/lib/Checker/SVals.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRState.h" #include "clang/Basic/IdentifierTable.h" using namespace clang; @@ -153,8 +153,8 @@ void SVal::symbol_iterator::expand() { assert(false && "unhandled expansion case"); } -const GRState *nonloc::LazyCompoundVal::getState() const { - return static_cast<const LazyCompoundValData*>(Data)->getState(); +const void *nonloc::LazyCompoundVal::getStore() const { + return static_cast<const LazyCompoundValData*>(Data)->getStore(); } const TypedRegion *nonloc::LazyCompoundVal::getRegion() const { @@ -299,7 +299,7 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const { } case nonloc::LazyCompoundValKind: { const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this); - os << "lazyCompoundVal{" << (void*) C.getState() << ',' << C.getRegion() + os << "lazyCompoundVal{" << (void*) C.getStore() << ',' << C.getRegion() << '}'; break; } diff --git a/lib/Analysis/SValuator.cpp b/lib/Checker/SValuator.cpp index 8392fcf65a2c..542fc1b1078d 100644 --- a/lib/Analysis/SValuator.cpp +++ b/lib/Checker/SValuator.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/SValuator.h" -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/SValuator.h" +#include "clang/Checker/PathSensitive/GRState.h" using namespace clang; @@ -53,25 +53,29 @@ DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST, ValMgr.getContext().IntTy)); } -SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, - QualType castTy, QualType originalTy){ - +SVal SValuator::EvalCast(SVal val, QualType castTy, QualType originalTy) { if (val.isUnknownOrUndef() || castTy == originalTy) - return CastResult(state, val); + return val; ASTContext &C = ValMgr.getContext(); // For const casts, just propagate the value. if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) if (C.hasSameUnqualifiedType(castTy, originalTy)) - return CastResult(state, val); + return val; + // Check for casts to real or complex numbers. We don't handle these at all + // right now. + if (castTy->isFloatingType() || castTy->isAnyComplexType()) + return UnknownVal(); + + // Check for casts from integers to integers. if (castTy->isIntegerType() && originalTy->isIntegerType()) - return CastResult(state, EvalCastNL(cast<NonLoc>(val), castTy)); + return EvalCastNL(cast<NonLoc>(val), castTy); // Check for casts from pointers to integers. if (castTy->isIntegerType() && Loc::IsLocType(originalTy)) - return CastResult(state, EvalCastL(cast<Loc>(val), castTy)); + return EvalCastL(cast<Loc>(val), castTy); // Check for casts from integers to pointers. if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) { @@ -79,10 +83,9 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, if (const MemRegion *R = LV->getLoc().getAsRegion()) { StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager(); R = storeMgr.CastRegion(R, castTy); - return R ? CastResult(state, loc::MemRegionVal(R)) - : CastResult(state, UnknownVal()); + return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } - return CastResult(state, LV->getLoc()); + return LV->getLoc(); } goto DispatchCast; } @@ -90,7 +93,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, // Just pass through function and block pointers. if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) { assert(Loc::IsLocType(castTy)); - return CastResult(state, val); + return val; } // Check for casts from array type to another type. @@ -101,7 +104,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, // Are we casting from an array to a pointer? If so just pass on // the decayed value. if (castTy->isPointerType()) - return CastResult(state, val); + return val; // Are we casting from an array to an integer? If so, cast the decayed // pointer value to an integer. @@ -111,7 +114,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, // need the original decayed type. // QualType elemTy = cast<ArrayType>(originalTy)->getElementType(); // QualType pointerTy = C.getPointerType(elemTy); - return CastResult(state, EvalCastL(cast<Loc>(val), castTy)); + return EvalCastL(cast<Loc>(val), castTy); } // Check for casts from a region to a specific type. @@ -144,21 +147,11 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, // different type. If the MemRegion* returned is NULL, this expression // evaluates to UnknownVal. R = storeMgr.CastRegion(R, castTy); - return R ? CastResult(state, loc::MemRegionVal(R)) - : CastResult(state, UnknownVal()); + return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } DispatchCast: // All other cases. - return CastResult(state, - isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy) - : EvalCastNL(cast<NonLoc>(val), castTy)); -} - -SValuator::DefinedOrUnknownCastResult -SValuator::EvalCast(DefinedOrUnknownSVal V, const GRState *ST, - QualType castTy, QualType originalType) { - SValuator::CastResult X = EvalCast((SVal) V, ST, castTy, originalType); - return DefinedOrUnknownCastResult(X.getState(), - cast<DefinedOrUnknownSVal>(X.getSVal())); + return isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy) + : EvalCastNL(cast<NonLoc>(val), castTy); } diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Checker/SimpleConstraintManager.cpp index eca20d574db3..8c423a99777d 100644 --- a/lib/Analysis/SimpleConstraintManager.cpp +++ b/lib/Checker/SimpleConstraintManager.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "SimpleConstraintManager.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/Checker.h" namespace clang { diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Checker/SimpleConstraintManager.h index 818239831948..5f20e0072b20 100644 --- a/lib/Analysis/SimpleConstraintManager.h +++ b/lib/Checker/SimpleConstraintManager.h @@ -14,8 +14,8 @@ #ifndef LLVM_CLANG_ANALYSIS_SIMPLE_CONSTRAINT_MANAGER_H #define LLVM_CLANG_ANALYSIS_SIMPLE_CONSTRAINT_MANAGER_H -#include "clang/Analysis/PathSensitive/ConstraintManager.h" -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/ConstraintManager.h" +#include "clang/Checker/PathSensitive/GRState.h" namespace clang { diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp index 8f2f5a1b134c..fb1d74a99046 100644 --- a/lib/Analysis/SimpleSValuator.cpp +++ b/lib/Checker/SimpleSValuator.cpp @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/SValuator.h" -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/SValuator.h" +#include "clang/Checker/PathSensitive/GRState.h" using namespace clang; @@ -423,6 +423,6 @@ SVal SimpleSValuator::EvalBinOpLN(const GRState *state, } // Delegate pointer arithmetic to the StoreManager. - return state->getStateManager().getStoreManager().EvalBinOp(state, op, lhs, + return state->getStateManager().getStoreManager().EvalBinOp(op, lhs, rhs, resultTy); } diff --git a/lib/Analysis/Store.cpp b/lib/Checker/Store.cpp index 1724a9250c25..e524cb3d7cc3 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Checker/Store.cpp @@ -11,15 +11,15 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/Store.h" -#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/Store.h" +#include "clang/Checker/PathSensitive/GRState.h" #include "clang/AST/CharUnits.h" using namespace clang; StoreManager::StoreManager(GRStateManager &stateMgr) : ValMgr(stateMgr.getValueManager()), StateMgr(stateMgr), - MRMgr(ValMgr.getRegionManager()) {} + MRMgr(ValMgr.getRegionManager()), Ctx(stateMgr.getContext()) {} const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base, QualType EleTy, uint64_t index) { @@ -31,7 +31,7 @@ const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base, static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { if (const RecordType *RT = Ty->getAs<RecordType>()) { const RecordDecl *D = RT->getDecl(); - if (!D->getDefinition(Ctx)) + if (!D->getDefinition()) return false; } @@ -224,27 +224,104 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, return V; } -const GRState *StoreManager::InvalidateRegions(const GRState *state, - const MemRegion * const *I, - const MemRegion * const *End, - const Expr *E, - unsigned Count, - InvalidatedSymbols *IS) { +Store StoreManager::InvalidateRegions(Store store, + const MemRegion * const *I, + const MemRegion * const *End, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS) { for ( ; I != End ; ++I) - state = InvalidateRegion(state, *I, E, Count, IS); + store = InvalidateRegion(store, *I, E, Count, IS); - return state; + return store; } -//===----------------------------------------------------------------------===// -// Common getLValueXXX methods. -//===----------------------------------------------------------------------===// +SVal StoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) { + if (Base.isUnknownOrUndef()) + return Base; + + Loc BaseL = cast<Loc>(Base); + const MemRegion* BaseR = 0; + + switch (BaseL.getSubKind()) { + case loc::MemRegionKind: + BaseR = cast<loc::MemRegionVal>(BaseL).getRegion(); + break; + + case loc::GotoLabelKind: + // These are anormal cases. Flag an undefined value. + return UndefinedVal(); + + case loc::ConcreteIntKind: + // While these seem funny, this can happen through casts. + // FIXME: What we should return is the field offset. For example, + // add the field offset to the integer value. That way funny things + // like this work properly: &(((struct foo *) 0xa)->f) + return Base; + + default: + assert(0 && "Unhandled Base."); + return Base; + } + + // NOTE: We must have this check first because ObjCIvarDecl is a subclass + // of FieldDecl. + if (const ObjCIvarDecl *ID = dyn_cast<ObjCIvarDecl>(D)) + return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR)); + + return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR)); +} + +SVal StoreManager::getLValueElement(QualType elementType, SVal Offset, + SVal Base) { + + // If the base is an unknown or undefined value, just return it back. + // FIXME: For absolute pointer addresses, we just return that value back as + // well, although in reality we should return the offset added to that + // value. + if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base)) + return Base; + + // Only handle integer offsets... for now. + if (!isa<nonloc::ConcreteInt>(Offset)) + return UnknownVal(); + + const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion(); + + // Pointer of any type can be cast and used as array base. + const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion); + + // Convert the offset to the appropriate size and signedness. + Offset = ValMgr.convertToArrayIndex(Offset); + + if (!ElemR) { + // + // If the base region is not an ElementRegion, create one. + // This can happen in the following example: + // + // char *p = __builtin_alloc(10); + // p[1] = 8; + // + // Observe that 'p' binds to an AllocaRegion. + // + return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset, + BaseRegion, Ctx)); + } + + SVal BaseIdx = ElemR->getIndex(); + + if (!isa<nonloc::ConcreteInt>(BaseIdx)) + return UnknownVal(); + + const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue(); + const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue(); + assert(BaseIdxI.isSigned()); + + // Compute the new index. + SVal NewIdx = nonloc::ConcreteInt( + ValMgr.getBasicValueFactory().getValue(BaseIdxI + OffI)); -/// getLValueCompoundLiteral - Returns an SVal representing the lvalue -/// of a compound literal. Within RegionStore a compound literal -/// has an associated region, and the lvalue of the compound literal -/// is the lvalue of that region. -SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL, - const LocationContext *LC) { - return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); + // Construct the new ElementRegion. + const MemRegion *ArrayR = ElemR->getSuperRegion(); + return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR, + Ctx)); } diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp index 3fe36b064e3d..40bdcf65bca4 100644 --- a/lib/Analysis/SymbolManager.cpp +++ b/lib/Checker/SymbolManager.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/SymbolManager.h" -#include "clang/Analysis/PathSensitive/MemRegion.h" +#include "clang/Checker/PathSensitive/SymbolManager.h" +#include "clang/Checker/PathSensitive/MemRegion.h" #include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Analysis/UndefBranchChecker.cpp b/lib/Checker/UndefBranchChecker.cpp index c739d1ac4b22..e047b187b108 100644 --- a/lib/Analysis/UndefBranchChecker.cpp +++ b/lib/Checker/UndefBranchChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Checker/PathSensitive/Checker.h" using namespace clang; diff --git a/lib/Checker/UndefCapturedBlockVarChecker.cpp b/lib/Checker/UndefCapturedBlockVarChecker.cpp new file mode 100644 index 000000000000..a8d7284b40ac --- /dev/null +++ b/lib/Checker/UndefCapturedBlockVarChecker.cpp @@ -0,0 +1,101 @@ +// UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This checker detects blocks that capture uninitialized values. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +namespace { +class UndefCapturedBlockVarChecker + : public CheckerVisitor<UndefCapturedBlockVarChecker> { + BugType *BT; + +public: + UndefCapturedBlockVarChecker() : BT(0) {} + static void *getTag() { static int tag = 0; return &tag; } + void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE); +}; +} // end anonymous namespace + +void clang::RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng) { + Eng.registerCheck(new UndefCapturedBlockVarChecker()); +} + +static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S, + const VarDecl *VD){ + if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S)) + if (BR->getDecl() == VD) + return BR; + + for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); + I!=E; ++I) + if (const Stmt *child = *I) { + const BlockDeclRefExpr *BR = FindBlockDeclRefExpr(child, VD); + if (BR) + return BR; + } + + return NULL; +} + +void +UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C, + const BlockExpr *BE) { + if (!BE->hasBlockDeclRefExprs()) + return; + + const GRState *state = C.getState(); + const BlockDataRegion *R = + cast<BlockDataRegion>(state->getSVal(BE).getAsRegion()); + + BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), + E = R->referenced_vars_end(); + + for (; I != E; ++I) { + // This VarRegion is the region associated with the block; we need + // the one associated with the encompassing context. + const VarRegion *VR = *I; + const VarDecl *VD = VR->getDecl(); + + if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) + continue; + + // Get the VarRegion associated with VD in the local stack frame. + const LocationContext *LC = C.getPredecessor()->getLocationContext(); + VR = C.getValueManager().getRegionManager().getVarRegion(VD, LC); + + if (state->getSVal(VR).isUndef()) + if (ExplodedNode *N = C.GenerateSink()) { + if (!BT) + BT = new BuiltinBug("Captured block variable is uninitialized"); + + // Generate a bug report. + llvm::SmallString<128> buf; + llvm::raw_svector_ostream os(buf); + + os << "Variable '" << VD->getName() << "' is captured by block with " + "a garbage value"; + + EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); + if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD)) + R->addRange(Ex->getSourceRange()); + R->addVisitorCreator(bugreporter::registerFindLastStore, VR); + // need location of block + C.EmitReport(R); + } + } +} diff --git a/lib/Analysis/UndefResultChecker.cpp b/lib/Checker/UndefResultChecker.cpp index acc86dda5a97..fb2283a62044 100644 --- a/lib/Analysis/UndefResultChecker.cpp +++ b/lib/Checker/UndefResultChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/BugReporter.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/Analysis/UndefinedArraySubscriptChecker.cpp b/lib/Checker/UndefinedArraySubscriptChecker.cpp index d6aacaf1f85e..a2792ad17ba1 100644 --- a/lib/Analysis/UndefinedArraySubscriptChecker.cpp +++ b/lib/Checker/UndefinedArraySubscriptChecker.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/BugReporter/BugReporter.h" #include "GRExprEngineInternalChecks.h" using namespace clang; diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Checker/UndefinedAssignmentChecker.cpp index 4630b823a91e..7c33c1d39235 100644 --- a/lib/Analysis/UndefinedAssignmentChecker.cpp +++ b/lib/Checker/UndefinedAssignmentChecker.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/BugReporter/BugReporter.h" using namespace clang; diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Checker/VLASizeChecker.cpp index 2690d6f0cffc..51ad1e2daf5e 100644 --- a/lib/Analysis/VLASizeChecker.cpp +++ b/lib/Checker/VLASizeChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/BugReporter.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/Analysis/ValueManager.cpp b/lib/Checker/ValueManager.cpp index d09137330cb2..5359489a2299 100644 --- a/lib/Analysis/ValueManager.cpp +++ b/lib/Checker/ValueManager.cpp @@ -13,8 +13,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/ValueManager.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Checker/PathSensitive/ValueManager.h" +#include "clang/Analysis/AnalysisContext.h" using namespace clang; using namespace llvm; diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index ca5b6fa97c26..46b62441d6e4 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -13,6 +13,7 @@ #include "CGDebugInfo.h" #include "CodeGenFunction.h" +#include "CGObjCRuntime.h" #include "CodeGenModule.h" #include "clang/AST/DeclObjC.h" #include "llvm/Module.h" @@ -176,7 +177,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // block literal. // __invoke CharUnits subBlockSize; - uint64_t subBlockAlign; + CharUnits subBlockAlign; llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; bool subBlockHasCopyDispose = false; llvm::Function *Fn @@ -249,7 +250,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true); llvm::AllocaInst *A = CreateTempAlloca(Ty); - A->setAlignment(subBlockAlign); + A->setAlignment(subBlockAlign.getQuantity()); V = A; std::vector<HelperInfo> NoteForHelper(subBlockDeclRefDecls.size()); @@ -355,7 +356,21 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { } QualType BPT = BE->getType(); - return Builder.CreateBitCast(V, ConvertType(BPT)); + V = Builder.CreateBitCast(V, ConvertType(BPT)); + // See if this is a __weak block variable and the must call objc_read_weak + // on it. + const FunctionType *ftype = BPT->getPointeeType()->getAs<FunctionType>(); + QualType RES = ftype->getResultType(); + if (RES.isObjCGCWeak()) { + // Must cast argument to id* + const llvm::Type *ObjectPtrTy = + ConvertType(CGM.getContext().getObjCIdType()); + const llvm::Type *PtrObjectPtrTy = + llvm::PointerType::getUnqual(ObjectPtrTy); + V = Builder.CreateBitCast(V, PtrObjectPtrTy); + V = CGM.getObjCRuntime().EmitObjCWeakRead(*this, V); + } + return V; } @@ -496,10 +511,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, // Load the function. llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp"); - QualType ResultType = FnType->getAs<FunctionType>()->getResultType(); + const FunctionType *FuncTy = FnType->getAs<FunctionType>(); + QualType ResultType = FuncTy->getResultType(); const CGFunctionInfo &FnInfo = - CGM.getTypes().getFunctionInfo(ResultType, Args); + CGM.getTypes().getFunctionInfo(ResultType, Args, FuncTy->getCallConv(), + FuncTy->getNoReturnAttr()); // Cast the function pointer to the right type. const llvm::Type *BlockFTy = @@ -593,8 +610,8 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // Block literal size. For global blocks we just use the size of the generic // block literal struct. - CharUnits BlockLiteralSize = CharUnits::fromQuantity( - TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8); + CharUnits BlockLiteralSize = + CGM.GetTargetTypeStoreSize(getGenericBlockLiteralType()); DescriptorFields[1] = llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize.getQuantity()); @@ -615,7 +632,7 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { CodeGenFunction::BlockInfo Info(0, n); CharUnits subBlockSize; - uint64_t subBlockAlign; + CharUnits subBlockAlign; llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; bool subBlockHasCopyDispose = false; llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; @@ -678,7 +695,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, const Decl *OuterFuncDecl, llvm::DenseMap<const Decl*, llvm::Value*> ldm, CharUnits &Size, - uint64_t &Align, + CharUnits &Align, llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls, bool &subBlockHasCopyDispose) { @@ -698,13 +715,14 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, LocalDeclMap[VD] = i->second; } - BlockOffset = CharUnits::fromQuantity( - CGM.getTargetData() - .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8); - BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; + BlockOffset = + CGM.GetTargetTypeStoreSize(CGM.getGenericBlockLiteralType()); + BlockAlign = getContext().getTypeAlignInChars(getContext().VoidPtrTy); const FunctionType *BlockFunctionType = BExpr->getFunctionType(); QualType ResultType; + CallingConv CC = BlockFunctionType->getCallConv(); + bool NoReturn = BlockFunctionType->getNoReturnAttr(); bool IsVariadic; if (const FunctionProtoType *FTy = dyn_cast<FunctionProtoType>(BlockFunctionType)) { @@ -743,7 +761,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, Args.push_back(std::make_pair(*i, (*i)->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(ResultType, Args); + CGM.getTypes().getFunctionInfo(ResultType, Args, CC, NoReturn); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic); @@ -777,10 +795,9 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, if (CGDebugInfo *DI = getDebugInfo()) { // Emit debug information for all the BlockDeclRefDecls. - for (unsigned i=0; i < BlockDeclRefDecls.size(); ++i) { - const Expr *E = BlockDeclRefDecls[i]; - const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); - if (BDRE) { + for (unsigned i = 0, e = BlockDeclRefDecls.size(); i != e; ++i) { + if (const BlockDeclRefExpr *BDRE = + dyn_cast<BlockDeclRefExpr>(BlockDeclRefDecls[i])) { const ValueDecl *D = BDRE->getDecl(); DI->setLocation(D->getLocation()); DI->EmitDeclareOfBlockDeclRefVariable(BDRE, @@ -798,9 +815,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, FinishFunction(cast<CompoundStmt>(BExpr->getBody())->getRBracLoc()); // The runtime needs a minimum alignment of a void *. - uint64_t MinAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; + CharUnits MinAlign = getContext().getTypeAlignInChars(getContext().VoidPtrTy); BlockOffset = CharUnits::fromQuantity( - llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign)); + llvm::RoundUpToAlignment(BlockOffset.getQuantity(), + MinAlign.getQuantity())); Size = BlockOffset; Align = BlockAlign; @@ -813,20 +831,20 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl()); CharUnits Size = getContext().getTypeSizeInChars(D->getType()); - uint64_t Align = getContext().getDeclAlignInBytes(D); + CharUnits Align = getContext().getDeclAlign(D); if (BDRE->isByRef()) { Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy); - Align = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; + Align = getContext().getTypeAlignInChars(getContext().VoidPtrTy); } - assert ((Align > 0) && "alignment must be 1 byte or more"); + assert ((Align.isPositive()) && "alignment must be 1 byte or more"); CharUnits OldOffset = BlockOffset; // Ensure proper alignment, even if it means we have to have a gap BlockOffset = CharUnits::fromQuantity( - llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align)); + llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align.getQuantity())); BlockAlign = std::max(Align, BlockAlign); CharUnits Pad = BlockOffset - OldOffset; @@ -868,7 +886,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); + CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. @@ -949,7 +967,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args); + CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. @@ -1033,7 +1051,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); + CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); @@ -1096,7 +1114,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args); + CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); 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 f42244c52e0e..a9f5ae05c109 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -177,8 +177,9 @@ public: /// BlockOffset - The offset in bytes for the next allocation of an /// imported block variable. CharUnits BlockOffset; - /// BlockAlign - Maximal alignment needed for the Block expressed in bytes. - uint64_t BlockAlign; + /// BlockAlign - Maximal alignment needed for the Block expressed in + /// characters. + CharUnits BlockAlign; /// getBlockOffset - Allocate an offset for the ValueDecl from a /// BlockDeclRefExpr in a block literal (BlockExpr). diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index f11d52e4334c..beaf7b89c003 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -304,6 +304,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Size = Builder.CreateIntCast(Size, llvm::Type::getInt32Ty(VMContext), false, "tmp"); return RValue::get(Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), Size, "tmp")); } + case Builtin::BIbzero: case Builtin::BI__builtin_bzero: { Value *Address = EmitScalarExpr(E->getArg(0)); Builder.CreateCall4(CGM.getMemSetFn(), Address, @@ -656,7 +657,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // Unknown builtin, for now just dump it out and return undef. if (hasAggregateLLVMType(E->getType())) - return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType()))); + return RValue::getAggregate(CreateMemTemp(E->getType())); return RValue::get(llvm::UndefValue::get(ConvertType(E->getType()))); } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 4323f84d9633..28c4c6b4b57b 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -165,7 +165,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const CovariantThunkAdjustment &Adjustment) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + QualType ResultType = FPT->getResultType(); FunctionArgList Args; ImplicitParamDecl *ThisDecl = @@ -190,7 +191,6 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, StartFunction(FD, ResultType, Fn, Args, SourceLocation()); // generate body - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), FPT->isVariadic()); @@ -232,7 +232,9 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType)); } - RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + 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() diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 2dda0b883f04..b064c125ad00 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -33,12 +33,19 @@ using namespace CodeGen; // FIXME: Use iterator and sidestep silly type array creation. +static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) { + switch (CC) { + default: return llvm::CallingConv::C; + case CC_X86StdCall: return llvm::CallingConv::X86_StdCall; + case CC_X86FastCall: return llvm::CallingConv::X86_FastCall; + } +} + const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) { - // FIXME: Set calling convention correctly, it needs to be associated with the - // type somehow. return getFunctionInfo(FTNP->getResultType(), - llvm::SmallVector<QualType, 16>(), 0); + llvm::SmallVector<QualType, 16>(), + FTNP->getCallConv(), FTNP->getNoReturnAttr()); } const @@ -47,20 +54,19 @@ CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) { // FIXME: Kill copy. for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - // FIXME: Set calling convention correctly, it needs to be associated with the - // type somehow. - return getFunctionInfo(FTP->getResultType(), ArgTys, 0); + return getFunctionInfo(FTP->getResultType(), ArgTys, + FTP->getCallConv(), FTP->getNoReturnAttr()); } -static unsigned getCallingConventionForDecl(const Decl *D) { +static CallingConv getCallingConventionForDecl(const Decl *D) { // Set the appropriate calling convention for the Function. if (D->hasAttr<StdCallAttr>()) - return llvm::CallingConv::X86_StdCall; + return CC_X86StdCall; if (D->hasAttr<FastCallAttr>()) - return llvm::CallingConv::X86_FastCall; + return CC_X86FastCall; - return llvm::CallingConv::C; + return CC_C; } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, @@ -75,7 +81,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, // FIXME: Set calling convention correctly, it needs to be associated with the // type somehow. - return getFunctionInfo(FTP->getResultType(), ArgTys, 0); + return getFunctionInfo(FTP->getResultType(), ArgTys, + FTP->getCallConv(), FTP->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { @@ -87,8 +94,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { const FunctionProtoType *FTP = MD->getType()->getAs<FunctionProtoType>(); for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, - getCallingConventionForDecl(MD)); + return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), + FTP->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, @@ -105,8 +112,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>(); for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, - getCallingConventionForDecl(D)); + return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), + FTP->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, @@ -123,8 +130,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>(); for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, - getCallingConventionForDecl(D)); + return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), + FTP->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { @@ -132,19 +139,19 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { if (MD->isInstance()) return getFunctionInfo(MD); - unsigned CallingConvention = getCallingConventionForDecl(FD); const FunctionType *FTy = FD->getType()->getAs<FunctionType>(); if (const FunctionNoProtoType *FNTP = dyn_cast<FunctionNoProtoType>(FTy)) return getFunctionInfo(FNTP->getResultType(), llvm::SmallVector<QualType, 16>(), - CallingConvention); + FNTP->getCallConv(), FNTP->getNoReturnAttr()); const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy); llvm::SmallVector<QualType, 16> ArgTys; // FIXME: Kill copy. for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i) ArgTys.push_back(FPT->getArgType(i)); - return getFunctionInfo(FPT->getResultType(), ArgTys, CallingConvention); + return getFunctionInfo(FPT->getResultType(), ArgTys, + FPT->getCallConv(), FPT->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { @@ -156,37 +163,56 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { e = MD->param_end(); i != e; ++i) ArgTys.push_back((*i)->getType()); return getFunctionInfo(MD->getResultType(), ArgTys, - getCallingConventionForDecl(MD)); + getCallingConventionForDecl(MD), + /*NoReturn*/ false); +} + +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) { + // FIXME: Do we need to handle ObjCMethodDecl? + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); + + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) + return getFunctionInfo(CD, GD.getCtorType()); + + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) + return getFunctionInfo(DD, GD.getDtorType()); + + return getFunctionInfo(FD); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const CallArgList &Args, - unsigned CallingConvention){ + CallingConv CC, + bool NoReturn) { // FIXME: Kill copy. llvm::SmallVector<QualType, 16> ArgTys; for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys, CallingConvention); + return getFunctionInfo(ResTy, ArgTys, CC, NoReturn); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const FunctionArgList &Args, - unsigned CallingConvention){ + CallingConv CC, + bool NoReturn) { // FIXME: Kill copy. llvm::SmallVector<QualType, 16> ArgTys; for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys, CallingConvention); + return getFunctionInfo(ResTy, ArgTys, CC, NoReturn); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const llvm::SmallVector<QualType, 16> &ArgTys, - unsigned CallingConvention){ + CallingConv CallConv, + bool NoReturn) { + unsigned CC = ClangCallConvToLLVMCallConv(CallConv); + // Lookup or create unique function info. llvm::FoldingSetNodeID ID; - CGFunctionInfo::Profile(ID, CallingConvention, ResTy, + CGFunctionInfo::Profile(ID, CC, NoReturn, ResTy, ArgTys.begin(), ArgTys.end()); void *InsertPos = 0; @@ -195,7 +221,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, return *FI; // Construct the function info. - FI = new CGFunctionInfo(CallingConvention, ResTy, ArgTys); + FI = new CGFunctionInfo(CC, NoReturn, ResTy, ArgTys); FunctionInfos.InsertNode(FI, InsertPos); // Compute ABI information. @@ -205,10 +231,12 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, } CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, + bool _NoReturn, QualType ResTy, const llvm::SmallVector<QualType, 16> &ArgTys) : CallingConvention(_CallingConvention), - EffectiveCallingConvention(_CallingConvention) + EffectiveCallingConvention(_CallingConvention), + NoReturn(_NoReturn) { NumArgs = ArgTys.size(); Args = new ArgInfo[1 + NumArgs]; @@ -258,7 +286,7 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV, QualType FT = FD->getType(); // FIXME: What are the right qualifiers here? - LValue LV = EmitLValueForField(Addr, FD, false, 0); + LValue LV = EmitLValueForField(Addr, FD, 0); if (CodeGenFunction::hasAggregateLLVMType(FT)) { AI = ExpandTypeFromArgs(FT, LV, AI); } else { @@ -285,7 +313,7 @@ CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV, QualType FT = FD->getType(); // FIXME: What are the right qualifiers here? - LValue LV = EmitLValueForField(Addr, FD, false, 0); + LValue LV = EmitLValueForField(Addr, FD, 0); if (CodeGenFunction::hasAggregateLLVMType(FT)) { ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()), Args); } else { @@ -490,6 +518,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, CallingConv = FI.getEffectiveCallingConvention(); + if (FI.isNoReturn()) + FuncAttrs |= llvm::Attribute::NoReturn; + // FIXME: handle sseregparm someday... if (TargetDecl) { if (TargetDecl->hasAttr<NoThrowAttr>()) @@ -685,7 +716,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Create a temporary alloca to hold the argument; the rest of // codegen expects to access aggregates & complex values by // reference. - V = CreateTempAlloca(ConvertTypeForMem(Ty)); + V = CreateMemTemp(Ty); Builder.CreateStore(AI, V); } else { if (!getContext().typesAreCompatible(Ty, Arg->getType())) { @@ -702,8 +733,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // If this structure was expanded into multiple arguments then // we need to create a temporary and reconstruct it from the // arguments. - llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(Ty), - Arg->getName() + ".addr"); + llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr"); // FIXME: What are the right qualifiers here? llvm::Function::arg_iterator End = ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI); @@ -719,7 +749,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, case ABIArgInfo::Ignore: // Initialize the local variable appropriately. if (hasAggregateLLVMType(Ty)) { - EmitParmDecl(*Arg, CreateTempAlloca(ConvertTypeForMem(Ty))); + EmitParmDecl(*Arg, CreateMemTemp(Ty)); } else { EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType()))); } @@ -732,7 +762,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // FIXME: This is very wasteful; EmitParmDecl is just going to drop the // result in a new alloca anyway, so we could just store into that // directly if we broke the abstraction down more. - llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(Ty), "coerce"); + llvm::Value *V = CreateMemTemp(Ty, "coerce"); CreateCoercedStore(AI, V, /*DestIsVolatile=*/false, *this); // Match to what EmitParmDecl is expecting for this type. if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { @@ -803,7 +833,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) { if (ArgType->isReferenceType()) - return EmitReferenceBindingToExpr(E, ArgType); + return EmitReferenceBindingToExpr(E); return EmitAnyExprToTemp(E); } @@ -827,7 +857,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (CGM.ReturnTypeUsesSret(CallInfo)) { llvm::Value *Value = ReturnValue.getValue(); if (!Value) - Value = CreateTempAlloca(ConvertTypeForMem(RetTy)); + Value = CreateMemTemp(RetTy); Args.push_back(Value); } @@ -843,7 +873,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::Indirect: if (RV.isScalar() || RV.isComplex()) { // Make a temporary alloca to pass the argument. - Args.push_back(CreateTempAlloca(ConvertTypeForMem(I->second))); + Args.push_back(CreateMemTemp(I->second)); if (RV.isScalar()) EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false, I->second); else @@ -874,10 +904,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // FIXME: Avoid the conversion through memory if possible. llvm::Value *SrcPtr; if (RV.isScalar()) { - SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce"); + SrcPtr = CreateMemTemp(I->second, "coerce"); EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, I->second); } else if (RV.isComplex()) { - SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce"); + SrcPtr = CreateMemTemp(I->second, "coerce"); StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false); } else SrcPtr = RV.getAggregateAddr(); @@ -982,7 +1012,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, bool DestIsVolatile = ReturnValue.isVolatile(); if (!DestPtr) { - DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "agg.tmp"); + DestPtr = CreateMemTemp(RetTy, "agg.tmp"); DestIsVolatile = false; } Builder.CreateStore(CI, DestPtr, DestIsVolatile); @@ -1000,7 +1030,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, bool DestIsVolatile = ReturnValue.isVolatile(); if (!DestPtr) { - DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "coerce"); + DestPtr = CreateMemTemp(RetTy, "coerce"); DestIsVolatile = false; } diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h index 427ab5f4cbc8..9601e9ae9a27 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -69,6 +69,9 @@ namespace CodeGen { /// depend on the ABI. unsigned EffectiveCallingConvention; + /// Whether this function is noreturn. + bool NoReturn; + unsigned NumArgs; ArgInfo *Args; @@ -77,6 +80,7 @@ namespace CodeGen { typedef ArgInfo *arg_iterator; CGFunctionInfo(unsigned CallingConvention, + bool NoReturn, QualType ResTy, const llvm::SmallVector<QualType, 16> &ArgTys); ~CGFunctionInfo() { delete[] Args; } @@ -88,6 +92,8 @@ namespace CodeGen { unsigned arg_size() const { return NumArgs; } + bool isNoReturn() const { return NoReturn; } + /// getCallingConvention - Return the user specified calling /// convention. unsigned getCallingConvention() const { return CallingConvention; } @@ -108,6 +114,7 @@ namespace CodeGen { void Profile(llvm::FoldingSetNodeID &ID) { ID.AddInteger(getCallingConvention()); + ID.AddBoolean(NoReturn); getReturnType().Profile(ID); for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it) it->type.Profile(ID); @@ -115,10 +122,12 @@ namespace CodeGen { template<class Iterator> static void Profile(llvm::FoldingSetNodeID &ID, unsigned CallingConvention, + bool NoReturn, QualType ResTy, Iterator begin, Iterator end) { ID.AddInteger(CallingConvention); + ID.AddBoolean(NoReturn); ResTy.Profile(ID); for (; begin != end; ++begin) begin->Profile(ID); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index a822ca2b7417..fa5a47f31564 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -19,11 +19,11 @@ using namespace clang; using namespace CodeGen; static uint64_t -ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths, +ComputeNonVirtualBaseClassOffset(ASTContext &Context, + const CXXBasePath &Path, unsigned Start) { uint64_t Offset = 0; - const CXXBasePath &Path = Paths.front(); for (unsigned i = Start, e = Path.size(); i != e; ++i) { const CXXBasePathElement& Element = Path[i]; @@ -44,20 +44,21 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths, } llvm::Constant * -CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl) { - if (ClassDecl == BaseClassDecl) +CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class, + const CXXRecordDecl *BaseClass) { + if (Class == BaseClass) return 0; CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast<CXXRecordDecl *>(ClassDecl)-> - isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) { + if (!const_cast<CXXRecordDecl *>(Class)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) { assert(false && "Class must be derived from the passed in base class!"); return 0; } - uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0); + uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), + Paths.front(), 0); if (!Offset) return 0; @@ -67,51 +68,6 @@ CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, return llvm::ConstantInt::get(PtrDiffTy, Offset); } -static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF, - llvm::Value *BaseValue, - 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 0; - } - - unsigned Start = 0; - llvm::Value *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 = - CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase); - - uint64_t Offset = - ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start); - - if (!Offset) - return VirtualOffset; - - const llvm::Type *PtrDiffTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); - llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset); - - if (VirtualOffset) - return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset); - - return NonVirtualOffset; -} - // 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. @@ -144,25 +100,91 @@ CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); uint64_t Offset = - ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start); + 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). +/// +/// The object pointed to by 'This' is assumed to be non-null. +llvm::Value * +CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, + bool isBaseVirtual, + const CXXRecordDecl *Derived, + const CXXRecordDecl *Base) { + // 'this' must be a pointer (in some address space) to Derived. + assert(This->getType()->isPointerTy() && + cast<llvm::PointerType>(This->getType())->getElementType() + == ConvertType(Derived)); + + // Compute the offset of the virtual base. + uint64_t Offset; + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived); + if (isBaseVirtual) + Offset = Layout.getVBaseClassOffset(Base); + else + Offset = Layout.getBaseClassOffset(Base); + + // Shift and cast down to the base type. + // TODO: for complete types, this should be possible with a GEP. + llvm::Value *V = This; + if (Offset) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); + V = Builder.CreateBitCast(V, Int8PtrTy); + V = Builder.CreateConstInBoundsGEP1_64(V, Offset / 8); + } + V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo()); + + return V; +} + llvm::Value * CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, + const CXXRecordDecl *Class, + const CXXRecordDecl *BaseClass, bool NullCheckValue) { QualType BTy = getContext().getCanonicalType( - getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl))); + getContext().getTypeDeclType(BaseClass)); const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy)); - if (ClassDecl == BaseClassDecl) { + if (Class == BaseClass) { // Just cast back. return Builder.CreateBitCast(Value, BasePtrTy); } + + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (!const_cast<CXXRecordDecl *>(Class)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return 0; + } + + unsigned Start = 0; + llvm::Value *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()); + } + } + + uint64_t Offset = + ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start); + if (!Offset && !VBase) { + // Just cast back. + return Builder.CreateBitCast(Value, BasePtrTy); + } + llvm::BasicBlock *CastNull = 0; llvm::BasicBlock *CastNotNull = 0; llvm::BasicBlock *CastEnd = 0; @@ -179,16 +201,27 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, EmitBlock(CastNotNull); } - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + if (VBase) + VirtualOffset = GetVirtualBaseClassOffset(Value, Class, VBase); - llvm::Value *Offset = - GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl); + const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); + llvm::Value *NonVirtualOffset = 0; + if (Offset) + NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset); - if (Offset) { - // Apply the offset. - Value = Builder.CreateBitCast(Value, Int8PtrTy); - Value = Builder.CreateGEP(Value, Offset, "add.ptr"); - } + llvm::Value *BaseOffset; + if (VBase) { + if (NonVirtualOffset) + BaseOffset = Builder.CreateAdd(VirtualOffset, NonVirtualOffset); + else + BaseOffset = VirtualOffset; + } else + BaseOffset = NonVirtualOffset; + + // Apply the base offset. + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); + Value = Builder.CreateBitCast(Value, Int8PtrTy); + Value = Builder.CreateGEP(Value, BaseOffset, "add.ptr"); // Cast back. Value = Builder.CreateBitCast(Value, BasePtrTy); @@ -212,19 +245,27 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, llvm::Value * CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *DerivedClassDecl, + const CXXRecordDecl *Class, + const CXXRecordDecl *DerivedClass, bool NullCheckValue) { QualType DerivedTy = getContext().getCanonicalType( - getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl))); + getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClass))); const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); - if (ClassDecl == DerivedClassDecl) { + if (Class == DerivedClass) { // Just cast back. return Builder.CreateBitCast(Value, DerivedPtrTy); } + llvm::Value *NonVirtualOffset = + CGM.GetNonVirtualBaseClassOffset(DerivedClass, Class); + + if (!NonVirtualOffset) { + // No offset, we can just cast back. + return Builder.CreateBitCast(Value, DerivedPtrTy); + } + llvm::BasicBlock *CastNull = 0; llvm::BasicBlock *CastNotNull = 0; llvm::BasicBlock *CastEnd = 0; @@ -241,17 +282,13 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, EmitBlock(CastNotNull); } - llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl, - ClassDecl); - if (Offset) { - // Apply the offset. - Value = Builder.CreatePtrToInt(Value, Offset->getType()); - Value = Builder.CreateSub(Value, Offset); - Value = Builder.CreateIntToPtr(Value, DerivedPtrTy); - } else { - // Just cast. - Value = Builder.CreateBitCast(Value, DerivedPtrTy); - } + // Apply the offset. + Value = Builder.CreatePtrToInt(Value, NonVirtualOffset->getType()); + Value = Builder.CreateSub(Value, NonVirtualOffset); + Value = Builder.CreateIntToPtr(Value, DerivedPtrTy); + + // Just cast. + Value = Builder.CreateBitCast(Value, DerivedPtrTy); if (NullCheckValue) { Builder.CreateBr(CastEnd); @@ -327,9 +364,9 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), BaseCopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + const FunctionProtoType *FPT + = BaseCopyCtor->getType()->getAs<FunctionProtoType>(); + EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); } EmitBlock(ContinueBlock); @@ -412,8 +449,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : RValue::getAggregate(Src); CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, MD); } EmitBlock(ContinueBlock); @@ -503,9 +539,9 @@ void CodeGenFunction::EmitClassMemberwiseCopy( // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), BaseCopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + const FunctionProtoType *FPT = + BaseCopyCtor->getType()->getAs<FunctionProtoType>(); + EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); } } @@ -550,9 +586,7 @@ void CodeGenFunction::EmitClassCopyAssignment( RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : RValue::getAggregate(Src); CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - QualType ResultType = - MD->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, MD); } @@ -629,8 +663,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0); + LValue LHS = EmitLValueForField(LoadOfThis, Field, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, Field, 0); if (Array) { const llvm::Type *BasePtr = ConvertType(FieldType); BasePtr = llvm::PointerType::getUnqual(BasePtr); @@ -647,26 +681,9 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, continue; } - if (Field->getType()->isReferenceType()) { - unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field); - - llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex, - "lhs.ref"); - - llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex, - "rhs.ref"); - - // Load the value in RHS. - RHS = Builder.CreateLoad(RHS); - - // And store it in the LHS - Builder.CreateStore(RHS, LHS); - - continue; - } // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0); + LValue LHS = EmitLValueForFieldInitialization(LoadOfThis, Field, 0); + LValue RHS = EmitLValueForFieldInitialization(LoadOfSrc, Field, 0); if (!hasAggregateLLVMType(Field->getType())) { RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); @@ -745,8 +762,8 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0); if (Array) { const llvm::Type *BasePtr = ConvertType(FieldType); BasePtr = llvm::PointerType::getUnqual(BasePtr); @@ -763,8 +780,8 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, continue; } // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0); if (!hasAggregateLLVMType(Field->getType())) { RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); @@ -810,29 +827,21 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, if (CtorType == Ctor_Base && isBaseVirtual) return; - // Compute the offset to the base; we do this directly instead of using - // GetAddressOfBaseClass because the class doesn't have a vtable pointer - // at this point. - // FIXME: This could be refactored back into GetAddressOfBaseClass if it took - // an extra parameter for whether the derived class is the complete object - // class. - const ASTRecordLayout &Layout = - CGF.getContext().getASTRecordLayout(ClassDecl); - uint64_t Offset; - if (isBaseVirtual) - Offset = Layout.getVBaseClassOffset(BaseClassDecl); - else - Offset = Layout.getBaseClassOffset(BaseClassDecl); - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - const llvm::Type *BaseClassType = CGF.ConvertType(QualType(BaseType, 0)); - llvm::Value *V = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy); - V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8); - V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo()); - - CGF.EmitCXXConstructorCall(BaseInit->getConstructor(), - Ctor_Base, V, - BaseInit->const_arg_begin(), - BaseInit->const_arg_end()); + // We can pretend to be a complete class because it only matters for + // virtual bases, and we only do virtual bases for complete ctors. + llvm::Value *V = ThisPtr; + V = CGF.GetAddressOfBaseOfCompleteClass(V, isBaseVirtual, + ClassDecl, BaseClassDecl); + + CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true); + + if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) { + // FIXME: Is this OK for C++0x delegating constructors? + CodeGenFunction::EHCleanupBlock Cleanup(CGF); + + CXXDestructorDecl *DD = BaseClassDecl->getDestructor(CGF.getContext()); + CGF.EmitCXXDestructorCall(DD, Dtor_Base, V); + } } static void EmitMemberInitializer(CodeGenFunction &CGF, @@ -846,91 +855,62 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, QualType FieldType = CGF.getContext().getCanonicalType(Field->getType()); llvm::Value *ThisPtr = CGF.LoadCXXThis(); - LValue LHS; - if (FieldType->isReferenceType()) { - // FIXME: This is really ugly; should be refactored somehow - unsigned idx = CGF.CGM.getTypes().getLLVMFieldNo(Field); - llvm::Value *V = CGF.Builder.CreateStructGEP(ThisPtr, idx, "tmp"); - assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); - LHS = LValue::MakeAddr(V, CGF.MakeQualifiers(FieldType)); - } else { - LHS = CGF.EmitLValueForField(ThisPtr, Field, ClassDecl->isUnion(), 0); - } - + LValue LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0); + // If we are initializing an anonymous union field, drill down to the field. if (MemberInit->getAnonUnionMember()) { Field = MemberInit->getAnonUnionMember(); - LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, - /*IsUnion=*/true, 0); + LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, 0); FieldType = Field->getType(); } - // If the field is an array, branch based on the element type. - const ConstantArrayType *Array = - CGF.getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = CGF.getContext().getBaseElementType(FieldType); - - // We lose the constructor for anonymous union members, so handle them - // explicitly. - // FIXME: This is somwhat ugly. - if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) { - if (MemberInit->getNumArgs()) - CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(), - LHS.isVolatileQualified()); - else - CGF.EmitAggregateClear(LHS.getAddress(), Field->getType()); - return; - } - - if (FieldType->getAs<RecordType>()) { - assert(MemberInit->getConstructor() && - "EmitCtorPrologue - no constructor to initialize member"); - if (Array) { - const llvm::Type *BasePtr = CGF.ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); - CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(), - Array, BaseAddrPtr, - MemberInit->const_arg_begin(), - MemberInit->const_arg_end()); - } - else - CGF.EmitCXXConstructorCall(MemberInit->getConstructor(), - Ctor_Complete, LHS.getAddress(), - MemberInit->const_arg_begin(), - MemberInit->const_arg_end()); - return; - } - - assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only"); - Expr *RhsExpr = *MemberInit->arg_begin(); + // FIXME: If there's no initializer and the CXXBaseOrMemberInitializer + // was implicitly generated, we shouldn't be zeroing memory. RValue RHS; if (FieldType->isReferenceType()) { - RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType, - /*IsInitializer=*/true); + RHS = CGF.EmitReferenceBindingToExpr(MemberInit->getInit(), + /*IsInitializer=*/true); CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); - } else if (Array) { + } else if (FieldType->isArrayType() && !MemberInit->getInit()) { CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType()); - } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) { - RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true)); + } else if (!CGF.hasAggregateLLVMType(Field->getType())) { + RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit(), true)); CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); - } else if (RhsExpr->getType()->isAnyComplexType()) { - CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(), + } else if (MemberInit->getInit()->getType()->isAnyComplexType()) { + CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(), LHS.isVolatileQualified()); } else { - // Handle member function pointers; other aggregates shouldn't get this far. - CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified()); + CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(), + LHS.isVolatileQualified(), false, true); + + if (!CGF.Exceptions) + return; + + const RecordType *RT = FieldType->getAs<RecordType>(); + if (!RT) + return; + + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (!RD->hasTrivialDestructor()) { + // FIXME: Is this OK for C++0x delegating constructors? + CodeGenFunction::EHCleanupBlock Cleanup(CGF); + + llvm::Value *ThisPtr = CGF.LoadCXXThis(); + LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0); + + CXXDestructorDecl *DD = RD->getDestructor(CGF.getContext()); + CGF.EmitCXXDestructorCall(DD, Dtor_Complete, LHS.getAddress()); + } } } /// EmitCtorPrologue - This routine generates necessary code to initialize /// base classes and non-static data members belonging to this constructor. -/// FIXME: This needs to take a CXXCtorType. void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType CtorType) { const CXXRecordDecl *ClassDecl = CD->getParent(); + + llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> MemberInitializers; // FIXME: Add vbase initialization @@ -945,14 +925,17 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, if (Member->isBaseInitializer()) EmitBaseInitializer(*this, ClassDecl, Member, CtorType); else - EmitMemberInitializer(*this, ClassDecl, Member); - - // Pop any live temporaries that the initializers might have pushed. - while (!LiveTemporaries.empty()) - PopCXXTemporary(); + MemberInitializers.push_back(Member); } InitializeVtablePtrs(ClassDecl); + + for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) { + assert(LiveTemporaries.empty() && + "Should not have any live temporaries at initializer start!"); + + EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I]); + } } /// EmitDtorEpilogue - Emit all code that comes at the end of class's @@ -1002,7 +985,6 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, llvm::Value *ThisPtr = LoadCXXThis(); LValue LHS = EmitLValueForField(ThisPtr, Field, - /*isUnion=*/false, // FIXME: Qualifiers? /*CVRQualifiers=*/0); if (Array) { @@ -1050,15 +1032,16 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) { const CXXBaseSpecifier &Base = *I; CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); + = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(), - ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); + llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(), + true, + ClassDecl, + BaseClassDecl); EmitCXXDestructorCall(D, Dtor_Base, V); } @@ -1080,7 +1063,7 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args, SourceLocation()); - + InitializeVtablePtrs(Dtor->getParent()); EmitDtorEpilogue(Dtor, DtorType); FinishFunction(); } @@ -1263,7 +1246,8 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, llvm::SmallString<16> Name; llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount); QualType R = getContext().VoidTy; - const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); + const CGFunctionInfo &FI + = CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, @@ -1295,20 +1279,21 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { - if (D->isCopyConstructor()) { - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext()); - if (ClassDecl->hasTrivialCopyConstructor()) { - assert(!ClassDecl->hasUserDeclaredCopyConstructor() && - "EmitCXXConstructorCall - user declared copy constructor"); - const Expr *E = (*ArgBeg); - QualType Ty = E->getType(); - llvm::Value *Src = EmitLValue(E).getAddress(); - EmitAggregateCopy(This, Src, Ty); + if (D->isTrivial()) { + if (ArgBeg == ArgEnd) { + // Trivial default constructor, no codegen required. + assert(D->isDefaultConstructor() && + "trivial 0-arg ctor not a default ctor"); return; } - } else if (D->isTrivial()) { - // FIXME: Track down why we're trying to generate calls to the trivial - // default constructor! + + assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor"); + assert(D->isCopyConstructor() && "trivial 1-arg ctor not a copy ctor"); + + const Expr *E = (*ArgBeg); + QualType Ty = E->getType(); + llvm::Value *Src = EmitLValue(E).getAddress(); + EmitAggregateCopy(This, Src, Ty); return; } @@ -1328,8 +1313,8 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, } llvm::Value * -CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, - const CXXRecordDecl *ClassDecl, +CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, + const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 1ffad3edcac7..5b9c6b055e0e 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -49,19 +49,21 @@ void CGDebugInfo::setLocation(SourceLocation Loc) { CurLoc = CGM.getContext().getSourceManager().getInstantiationLoc(Loc); } -/// getContext - Get context info for the decl. -llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl, - llvm::DIDescriptor &CompileUnit) { - if (Decl->isFileVarDecl()) +/// getContextDescriptor - Get context info for the decl. +llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context, + llvm::DIDescriptor &CompileUnit) { + if (!Context) return CompileUnit; - if (Decl->getDeclContext()->isFunctionOrMethod()) { - // Find the last subprogram in region stack. - for (unsigned RI = RegionStack.size(), RE = 0; RI != RE; --RI) { - llvm::DIDescriptor R(RegionStack[RI - 1]); - if (R.isSubprogram()) - return R; - } - } + + llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator + I = RegionMap.find(Context); + if (I != RegionMap.end()) + return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(I->second)); + + // Check namespace. + if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) + return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl, CompileUnit)); + return CompileUnit; } @@ -78,10 +80,9 @@ llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { std::string NS = FD->getNameAsString(); // Copy this name on the side and use its reference. - unsigned Length = NS.length() + 1; - char *StrPtr = FunctionNames.Allocate<char>(Length); - strncpy(StrPtr, NS.c_str(), Length); - return llvm::StringRef(StrPtr); + char *StrPtr = DebugInfoNames.Allocate<char>(NS.length()); + memcpy(StrPtr, NS.data(), NS.length()); + return llvm::StringRef(StrPtr, NS.length()); } /// getOrCreateCompileUnit - Get the compile unit from the cache or create a new @@ -90,16 +91,15 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Get source file information. const char *FileName = "<unknown>"; SourceManager &SM = CGM.getContext().getSourceManager(); - unsigned FID = 0; if (Loc.isValid()) { PresumedLoc PLoc = SM.getPresumedLoc(Loc); FileName = PLoc.getFilename(); - FID = PLoc.getIncludeLoc().getRawEncoding(); - } + unsigned FID = PLoc.getIncludeLoc().getRawEncoding(); - // See if this compile unit has been used before. - llvm::DICompileUnit &Unit = CompileUnitCache[FID]; - if (!Unit.isNull()) return Unit; + // See if this compile unit has been used before for this valid location. + llvm::DICompileUnit &Unit = CompileUnitCache[FID]; + if (!Unit.isNull()) return Unit; + } // Get absolute path name. llvm::sys::Path AbsFileName(FileName); @@ -149,9 +149,16 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1; // Create new compile unit. - return Unit = DebugFactory.CreateCompileUnit( + llvm::DICompileUnit Unit = DebugFactory.CreateCompileUnit( LangTag, AbsFileName.getLast(), AbsFileName.getDirname(), Producer, isMain, LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers); + + if (Loc.isValid()) { + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + unsigned FID = PLoc.getIncludeLoc().getRawEncoding(); + CompileUnitCache[FID] = Unit; + } + return Unit; } /// CreateType - Get the Basic type from the cache or create a new @@ -419,17 +426,18 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, // We don't set size information, but do specify where the typedef was // declared. - SourceLocation DefLoc = Ty->getDecl()->getLocation(); - llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); + PresumedLoc PLoc = SM.getPresumedLoc(Ty->getDecl()->getLocation()); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); + llvm::DIDescriptor TyContext + = getContextDescriptor(dyn_cast<Decl>(Ty->getDecl()->getDeclContext()), + Unit); llvm::DIType DbgTy = - DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit, - Ty->getDecl()->getName(), - DefUnit, Line, 0, 0, 0, 0, Src); + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, + TyContext, + Ty->getDecl()->getName(), Unit, + Line, 0, 0, 0, 0, Src); return DbgTy; } @@ -463,22 +471,21 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, /// CollectRecordFields - A helper function to collect debug info for /// record fields. This is used while creating debug info entry for a Record. void CGDebugInfo:: -CollectRecordFields(const RecordDecl *Decl, - llvm::DICompileUnit Unit, +CollectRecordFields(const RecordDecl *RD, llvm::DICompileUnit Unit, llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) { unsigned FieldNo = 0; SourceManager &SM = CGM.getContext().getSourceManager(); - const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl); - for (RecordDecl::field_iterator I = Decl->field_begin(), - E = Decl->field_end(); + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + for (RecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I, ++FieldNo) { FieldDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); llvm::StringRef FieldName = Field->getName(); - // Ignore unnamed fields. - if (FieldName.empty()) + // Ignore unnamed fields. Do not ignore unnamed records. + if (FieldName.empty() && !isa<RecordType>(Field->getType())) continue; // Get the location for the field. @@ -519,87 +526,264 @@ CollectRecordFields(const RecordDecl *Decl, } } +/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This +/// function type is not updated to include implicit "this" pointer. Use this +/// routine to get a method type which includes "this" pointer. +llvm::DIType +CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, + llvm::DICompileUnit Unit) { + llvm::DIType FnTy = getOrCreateType(Method->getType(), Unit); + + // Static methods do not need "this" pointer argument. + if (Method->isStatic()) + return FnTy; + + // Add "this" pointer. + + llvm::DIArray Args = llvm::DICompositeType(FnTy.getNode()).getTypeArray(); + assert (Args.getNumElements() && "Invalid number of arguments!"); + + llvm::SmallVector<llvm::DIDescriptor, 16> Elts; + + // First element is always return type. For 'void' functions it is NULL. + Elts.push_back(Args.getElement(0)); + + // "this" pointer is always first argument. + ASTContext &Context = CGM.getContext(); + QualType ThisPtr = + Context.getPointerType(Context.getTagDeclType(Method->getParent())); + llvm::DIType ThisPtrType = + DebugFactory.CreateArtificialType(getOrCreateType(ThisPtr, Unit)); + TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType.getNode(); + Elts.push_back(ThisPtrType); + + // Copy rest of the arguments. + for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i) + Elts.push_back(Args.getElement(i)); + + llvm::DIArray EltTypeArray = + DebugFactory.GetOrCreateArray(Elts.data(), Elts.size()); + + return + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type, + Unit, "", llvm::DICompileUnit(), + 0, 0, 0, 0, 0, + llvm::DIType(), EltTypeArray); +} + +/// CreateCXXMemberFunction - A helper function to create a DISubprogram for +/// a single member function GlobalDecl. +llvm::DISubprogram +CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, + llvm::DICompileUnit Unit, + llvm::DICompositeType &RecordTy) { + bool IsCtorOrDtor = + isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method); + + llvm::StringRef MethodName = getFunctionName(Method); + llvm::StringRef MethodLinkageName; + llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit); + + // Since a single ctor/dtor corresponds to multiple functions, it doesn't + // make sense to give a single ctor/dtor a linkage name. + if (!IsCtorOrDtor) + MethodLinkageName = CGM.getMangledName(Method); + + SourceManager &SM = CGM.getContext().getSourceManager(); + + // Get the location for the method. + SourceLocation MethodDefLoc = Method->getLocation(); + PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc); + llvm::DICompileUnit MethodDefUnit; + unsigned MethodLine = 0; + + if (!PLoc.isInvalid()) { + MethodDefUnit = getOrCreateCompileUnit(MethodDefLoc); + MethodLine = PLoc.getLine(); + } + + // Collect virtual method info. + llvm::DIType ContainingType; + unsigned Virtuality = 0; + unsigned VIndex = 0; + + if (Method->isVirtual()) { + if (Method->isPure()) + Virtuality = llvm::dwarf::DW_VIRTUALITY_pure_virtual; + else + Virtuality = llvm::dwarf::DW_VIRTUALITY_virtual; + + // 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); + ContainingType = RecordTy; + } + + llvm::DISubprogram SP = + DebugFactory.CreateSubprogram(RecordTy , MethodName, MethodName, + MethodLinkageName, + MethodDefUnit, MethodLine, + MethodTy, /*isLocalToUnit=*/false, + Method->isThisDeclarationADefinition(), + Virtuality, VIndex, ContainingType); + + // Don't cache ctors or dtors since we have to emit multiple functions for + // a single ctor or dtor. + if (!IsCtorOrDtor && Method->isThisDeclarationADefinition()) + SPCache[Method] = llvm::WeakVH(SP.getNode()); + + return SP; +} + /// CollectCXXMemberFunctions - A helper function to collect debug info for /// C++ member functions.This is used while creating debug info entry for /// a Record. void CGDebugInfo:: -CollectCXXMemberFunctions(const CXXRecordDecl *Decl, - llvm::DICompileUnit Unit, +CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DICompileUnit Unit, llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys, llvm::DICompositeType &RecordTy) { - SourceManager &SM = CGM.getContext().getSourceManager(); - for(CXXRecordDecl::method_iterator I = Decl->method_begin(), - E = Decl->method_end(); I != E; ++I) { - CXXMethodDecl *Method = *I; - llvm::StringRef MethodName; - llvm::StringRef MethodLinkageName; - llvm::DIType MethodTy = getOrCreateType(Method->getType(), Unit); - if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(Method)) { - if (CDecl->isImplicit()) - continue; - MethodName = Decl->getName(); - // FIXME : Find linkage name. - } else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(Method)) { - if (DDecl->isImplicit()) - continue; - MethodName = getFunctionName(Method); - // FIXME : Find linkage name. - } else { - if (Method->isImplicit()) - continue; - // regular method - MethodName = getFunctionName(Method); - MethodLinkageName = CGM.getMangledName(Method); - } - - // Get the location for the method. - SourceLocation MethodDefLoc = Method->getLocation(); - PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc); - llvm::DICompileUnit MethodDefUnit; - unsigned MethodLine = 0; - - if (!PLoc.isInvalid()) { - MethodDefUnit = getOrCreateCompileUnit(MethodDefLoc); - MethodLine = PLoc.getLine(); - } + for(CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *Method = *I; + + if (Method->isImplicit() && !Method->isUsed()) + continue; - llvm::DISubprogram SP = - DebugFactory.CreateSubprogram(RecordTy , MethodName, MethodName, - MethodLinkageName, - MethodDefUnit, MethodLine, - MethodTy, false, - Method->isThisDeclarationADefinition(), - 0 /*Virtuality*/, 0 /*VIndex*/, - llvm::DIType() /*ContainingType*/); - if (Method->isThisDeclarationADefinition()) - SPCache[cast<FunctionDecl>(Method)] = llvm::WeakVH(SP.getNode()); - EltTys.push_back(SP); + EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy)); } } +/// CollectCXXBases - A helper function to collect debug info for +/// C++ base classes. This is used while creating debug info entry for +/// a Record. +void CGDebugInfo:: +CollectCXXBases(const CXXRecordDecl *RD, llvm::DICompileUnit Unit, + llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys, + llvm::DICompositeType &RecordTy) { + + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); BI != BE; ++BI) { + unsigned BFlags = 0; + uint64_t BaseOffset; + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl()); + + if (BI->isVirtual()) { + // virtual base offset index is -ve. The code generator emits dwarf + // expression where it expects +ve number. + BaseOffset = 0 - CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base); + BFlags = llvm::DIType::FlagVirtual; + } else + BaseOffset = RL.getBaseClassOffset(Base); + + AccessSpecifier Access = BI->getAccessSpecifier(); + if (Access == clang::AS_private) + BFlags |= llvm::DIType::FlagPrivate; + else if (Access == clang::AS_protected) + BFlags |= llvm::DIType::FlagProtected; + + llvm::DIType DTy = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance, + RecordTy, llvm::StringRef(), + llvm::DICompileUnit(), 0, 0, 0, + BaseOffset, BFlags, + getOrCreateType(BI->getType(), + Unit)); + EltTys.push_back(DTy); + } +} + +/// getOrCreateVTablePtrType - Return debug info descriptor for vtable. +llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DICompileUnit Unit) { + if (!VTablePtrType.isNull()) + return VTablePtrType; + + 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::DIType SubTy = + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type, + Unit, "", llvm::DICompileUnit(), + 0, 0, 0, 0, 0, llvm::DIType(), SElements); + + unsigned Size = Context.getTypeSize(Context.VoidPtrTy); + llvm::DIType vtbl_ptr_type + = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, + Unit, "__vtbl_ptr_type", llvm::DICompileUnit(), + 0, Size, 0, 0, 0, SubTy); + + VTablePtrType = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, + Unit, "", llvm::DICompileUnit(), + 0, Size, 0, 0, 0, vtbl_ptr_type); + return VTablePtrType; +} + +/// getVtableName - Get vtable name for the given Class. +llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) { + // Otherwise construct gdb compatible name name. + std::string Name = "_vptr$" + RD->getNameAsString(); + + // Copy this name on the side and use its reference. + char *StrPtr = DebugInfoNames.Allocate<char>(Name.length()); + memcpy(StrPtr, Name.data(), Name.length()); + return llvm::StringRef(StrPtr, Name.length()); +} + + +/// CollectVtableInfo - If the C++ class has vtable info then insert appropriate +/// debug info entry in EltTys vector. +void CGDebugInfo:: +CollectVtableInfo(const CXXRecordDecl *RD, llvm::DICompileUnit Unit, + llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) { + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + + // If there is a primary base then it will hold vtable info. + if (RL.getPrimaryBase()) + return; + + // If this class is not dynamic then there is not any vtable info to collect. + if (!RD->isDynamicClass()) + return; + + unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); + llvm::DIType VPTR + = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, + getVtableName(RD), llvm::DICompileUnit(), + 0, Size, 0, 0, 0, + getOrCreateVTablePtrType(Unit)); + EltTys.push_back(VPTR); +} + /// CreateType - get structure or union type. llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, llvm::DICompileUnit Unit) { - RecordDecl *Decl = Ty->getDecl(); + RecordDecl *RD = Ty->getDecl(); unsigned Tag; - if (Decl->isStruct()) + if (RD->isStruct()) Tag = llvm::dwarf::DW_TAG_structure_type; - else if (Decl->isUnion()) + else if (RD->isUnion()) Tag = llvm::dwarf::DW_TAG_union_type; else { - assert(Decl->isClass() && "Unknown RecordType!"); + assert(RD->isClass() && "Unknown RecordType!"); Tag = llvm::dwarf::DW_TAG_class_type; } SourceManager &SM = CGM.getContext().getSourceManager(); // Get overall information about the record type for the debug info. - PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); + PresumedLoc PLoc = SM.getPresumedLoc(RD->getLocation()); llvm::DICompileUnit DefUnit; unsigned Line = 0; if (!PLoc.isInvalid()) { - DefUnit = getOrCreateCompileUnit(Decl->getLocation()); + DefUnit = getOrCreateCompileUnit(RD->getLocation()); Line = PLoc.getLine(); } @@ -610,19 +794,19 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. - // A Decl->getName() is not unique. However, the debug info descriptors - // are uniqued. The debug info descriptor describing record's context is - // necessary to keep two Decl's descriptor unique if their name match. - // FIXME : Use RecordDecl's DeclContext's descriptor. As a temp. step - // use type's name in FwdDecl. + // A RD->getName() is not unique. However, the debug info descriptors + // are uniqued so use type name to ensure uniquness. std::string STy = QualType(Ty, 0).getAsString(); + llvm::DIDescriptor FDContext = + getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit); llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, Unit, STy.c_str(), + DebugFactory.CreateCompositeType(Tag, FDContext, + STy.c_str(), DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray()); // If this is just a forward declaration, return it. - if (!Decl->getDefinition(CGM.getContext())) + if (!RD->getDefinition()) return FwdDecl; llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); @@ -633,10 +817,25 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; - CollectRecordFields(Decl, Unit, EltTys); - if (CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(Decl)) + const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); + if (CXXDecl) { + CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl); + CollectVtableInfo(CXXDecl, Unit, EltTys); + } + CollectRecordFields(RD, Unit, EltTys); + llvm::MDNode *ContainingType = NULL; + if (CXXDecl) { CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl); + // A class's primary base or the class itself contains the vtable. + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) + ContainingType = + getOrCreateType(QualType(PBase->getTypeForDecl(), 0), Unit).getNode(); + else if (CXXDecl->isDynamicClass()) + ContainingType = FwdDecl.getNode(); + } + llvm::DIArray Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); @@ -644,10 +843,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, uint64_t Size = CGM.getContext().getTypeSize(Ty); uint64_t Align = CGM.getContext().getTypeAlign(Ty); + llvm::DIDescriptor RDContext = + getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit); llvm::DICompositeType RealDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), + DebugFactory.CreateCompositeType(Tag, RDContext, + RD->getName(), DefUnit, Line, Size, Align, 0, 0, - llvm::DIType(), Elements); + llvm::DIType(), Elements, + 0, ContainingType); // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. @@ -659,14 +862,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, /// CreateType - get objective-c interface type. llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit Unit) { - ObjCInterfaceDecl *Decl = Ty->getDecl(); + ObjCInterfaceDecl *ID = Ty->getDecl(); unsigned Tag = llvm::dwarf::DW_TAG_structure_type; SourceManager &SM = CGM.getContext().getSourceManager(); // Get overall information about the record type for the debug info. - llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation()); - PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); + llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(ID->getLocation()); + PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation()); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -679,13 +882,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), + DebugFactory.CreateCompositeType(Tag, Unit, ID->getName(), DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray(), RuntimeLang); // If this is just a forward declaration, return it. - if (Decl->isForwardDecl()) + if (ID->isForwardDecl()) return FwdDecl; llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); @@ -696,7 +899,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; - ObjCInterfaceDecl *SClass = Decl->getSuperClass(); + ObjCInterfaceDecl *SClass = ID->getSuperClass(); if (SClass) { llvm::DIType SClassTy = getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit); @@ -707,11 +910,11 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, EltTys.push_back(InhTag); } - const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(Decl); + const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID); unsigned FieldNo = 0; - for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(), - E = Decl->ivar_end(); I != E; ++I, ++FieldNo) { + for (ObjCInterfaceDecl::ivar_iterator I = ID->ivar_begin(), + E = ID->ivar_end(); I != E; ++I, ++FieldNo) { ObjCIvarDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); @@ -769,7 +972,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, uint64_t Align = CGM.getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit, + DebugFactory.CreateCompositeType(Tag, Unit, ID->getName(), DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), Elements, RuntimeLang); @@ -782,13 +985,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::DICompileUnit Unit) { - EnumDecl *Decl = Ty->getDecl(); + EnumDecl *ED = Ty->getDecl(); llvm::SmallVector<llvm::DIDescriptor, 32> Enumerators; // Create DIEnumerator elements for each enumerator. for (EnumDecl::enumerator_iterator - Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end(); + Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end(); Enum != EnumEnd; ++Enum) { Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getName(), Enum->getInitVal().getZExtValue())); @@ -798,7 +1001,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::DIArray EltArray = DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size()); - SourceLocation DefLoc = Decl->getLocation(); + SourceLocation DefLoc = ED->getLocation(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); @@ -815,7 +1018,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::DIType DbgTy = DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, - Unit, Decl->getName(), DefUnit, Line, + Unit, ED->getName(), DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), EltArray); return DbgTy; @@ -1083,6 +1286,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(FI->second)); if (!SP.isNull() && SP.isSubprogram() && SP.isDefinition()) { RegionStack.push_back(SP.getNode()); + RegionMap[D] = llvm::WeakVH(SP.getNode()); return; } } @@ -1113,6 +1317,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, // Push function on region stack. RegionStack.push_back(SP.getNode()); + RegionMap[D] = llvm::WeakVH(SP.getNode()); } @@ -1164,160 +1369,172 @@ void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) { RegionStack.pop_back(); } -/// EmitDeclare - Emit local variable declaration debug info. -void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, - llvm::Value *Storage, CGBuilderTy &Builder) { - assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); - - // Do not emit variable debug information while generating optimized code. - // The llvm optimizer and code generator are not yet ready to support - // optimized code debugging. - const CodeGenOptions &CGO = CGM.getCodeGenOpts(); - if (CGO.OptimizationLevel) - return; - - llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); - QualType Type = Decl->getType(); - llvm::DIType Ty = getOrCreateType(Type, Unit); - if (Decl->hasAttr<BlocksAttr>()) { - llvm::DICompileUnit DefUnit; - unsigned Tag = llvm::dwarf::DW_TAG_structure_type; +// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. +// See BuildByRefType. +llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, + uint64_t *XOffset) { - llvm::SmallVector<llvm::DIDescriptor, 5> EltTys; - - llvm::DIType FieldTy; + llvm::SmallVector<llvm::DIDescriptor, 5> EltTys; - QualType FType; - uint64_t FieldSize, FieldOffset; - unsigned FieldAlign; + QualType FType; + uint64_t FieldSize, FieldOffset; + unsigned FieldAlign; + + llvm::DICompileUnit Unit = getOrCreateCompileUnit(VD->getLocation()); + QualType Type = VD->getType(); - llvm::DIArray Elements; - llvm::DIType EltTy; - - // Build up structure for the byref. See BuildByRefType. - FieldOffset = 0; + FieldOffset = 0; + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); + llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); + FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, + "__isa", llvm::DICompileUnit(), + 0, FieldSize, FieldAlign, + FieldOffset, 0, FieldTy); + EltTys.push_back(FieldTy); + FieldOffset += FieldSize; + + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); + FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, + "__forwarding", llvm::DICompileUnit(), + 0, FieldSize, FieldAlign, + FieldOffset, 0, FieldTy); + EltTys.push_back(FieldTy); + FieldOffset += FieldSize; + + FType = CGM.getContext().IntTy; + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); + FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, + "__flags", llvm::DICompileUnit(), + 0, FieldSize, FieldAlign, + FieldOffset, 0, FieldTy); + EltTys.push_back(FieldTy); + FieldOffset += FieldSize; + + FType = CGM.getContext().IntTy; + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); + FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, + "__size", llvm::DICompileUnit(), + 0, FieldSize, FieldAlign, + FieldOffset, 0, FieldTy); + EltTys.push_back(FieldTy); + FieldOffset += FieldSize; + + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); + if (HasCopyAndDispose) { FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__isa", DefUnit, + "__copy_helper", + llvm::DICompileUnit(), 0, FieldSize, FieldAlign, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); FieldOffset += FieldSize; - + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__forwarding", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__flags", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__size", DefUnit, + "__destroy_helper", + llvm::DICompileUnit(), 0, FieldSize, FieldAlign, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); FieldOffset += FieldSize; + } + + CharUnits Align = CGM.getContext().getDeclAlign(VD); + if (Align > CharUnits::fromQuantity( + CGM.getContext().Target.getPointerAlign(0) / 8)) { + unsigned AlignedOffsetInBytes + = llvm::RoundUpToAlignment(FieldOffset/8, Align.getQuantity()); + unsigned NumPaddingBytes + = AlignedOffsetInBytes - FieldOffset/8; - bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); - if (HasCopyAndDispose) { - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__copy_helper", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); + if (NumPaddingBytes > 0) { + llvm::APInt pad(32, NumPaddingBytes); + FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, + pad, ArrayType::Normal, 0); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__destroy_helper", DefUnit, + FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, + Unit, "", llvm::DICompileUnit(), 0, FieldSize, FieldAlign, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); FieldOffset += FieldSize; } - - unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl); - if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) { - unsigned AlignedOffsetInBytes - = llvm::RoundUpToAlignment(FieldOffset/8, Align); - unsigned NumPaddingBytes - = AlignedOffsetInBytes - FieldOffset/8; - - if (NumPaddingBytes > 0) { - llvm::APInt pad(32, NumPaddingBytes); - FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, - pad, ArrayType::Normal, 0); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, - Unit, "", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - } - } - - FType = Type; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = Align*8; - - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - Decl->getName(), DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); - - unsigned Flags = llvm::DIType::FlagBlockByrefStruct; + } + + FType = Type; + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = Align.getQuantity()*8; - Ty = DebugFactory.CreateCompositeType(Tag, Unit, "", + *XOffset = FieldOffset; + FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, + VD->getName(), llvm::DICompileUnit(), + 0, FieldSize, FieldAlign, + FieldOffset, 0, FieldTy); + EltTys.push_back(FieldTy); + FieldOffset += FieldSize; + + llvm::DIArray Elements = + DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); + + unsigned Flags = llvm::DIType::FlagBlockByrefStruct; + + return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type, + Unit, "", llvm::DICompileUnit(), 0, FieldOffset, 0, 0, Flags, llvm::DIType(), Elements); - } + +} +/// EmitDeclare - Emit local variable declaration debug info. +void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, + llvm::Value *Storage, CGBuilderTy &Builder) { + assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); + + // Do not emit variable debug information while generating optimized code. + // The llvm optimizer and code generator are not yet ready to support + // optimized code debugging. + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); + if (CGO.OptimizationLevel) + return; + + llvm::DICompileUnit Unit = getOrCreateCompileUnit(VD->getLocation()); + llvm::DIType Ty; + uint64_t XOffset = 0; + if (VD->hasAttr<BlocksAttr>()) + Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset); + else + Ty = getOrCreateType(VD->getType(), Unit); // Get location information. SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); + PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation()); unsigned Line = 0; unsigned Column = 0; - if (!PLoc.isInvalid()) { + if (PLoc.isInvalid()) + PLoc = SM.getPresumedLoc(CurLoc); + if (PLoc.isValid()) { Line = PLoc.getLine(); Column = PLoc.getColumn(); + Unit = getOrCreateCompileUnit(CurLoc); } else { Unit = llvm::DICompileUnit(); } @@ -1325,7 +1542,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, // Create the descriptor for the variable. llvm::DIVariable D = DebugFactory.CreateVariable(Tag, llvm::DIDescriptor(RegionStack.back()), - Decl->getName(), + VD->getName(), Unit, Line, Ty); // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = @@ -1342,7 +1559,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, llvm::Value *Storage, CGBuilderTy &Builder, CodeGenFunction *CGF) { - const ValueDecl *Decl = BDRE->getDecl(); + const ValueDecl *VD = BDRE->getDecl(); assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); // Do not emit variable debug information while generating optimized code. @@ -1353,186 +1570,50 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, return; uint64_t XOffset = 0; - llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); - QualType Type = Decl->getType(); - llvm::DIType Ty = getOrCreateType(Type, Unit); - if (Decl->hasAttr<BlocksAttr>()) { - llvm::DICompileUnit DefUnit; - unsigned Tag = llvm::dwarf::DW_TAG_structure_type; - - llvm::SmallVector<llvm::DIDescriptor, 5> EltTys; - - llvm::DIType FieldTy; - - QualType FType; - uint64_t FieldSize, FieldOffset; - unsigned FieldAlign; - - llvm::DIArray Elements; - llvm::DIType EltTy; - - // Build up structure for the byref. See BuildByRefType. - FieldOffset = 0; - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__isa", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__forwarding", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__flags", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__size", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); - if (HasCopyAndDispose) { - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__copy_helper", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__destroy_helper", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - } - - unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl); - if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) { - unsigned AlignedOffsetInBytes - = llvm::RoundUpToAlignment(FieldOffset/8, Align); - unsigned NumPaddingBytes - = AlignedOffsetInBytes - FieldOffset/8; - - if (NumPaddingBytes > 0) { - llvm::APInt pad(32, NumPaddingBytes); - FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, - pad, ArrayType::Normal, 0); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, - Unit, "", DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - } - } - - FType = Type; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = Align*8; - - XOffset = FieldOffset; - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - Decl->getName(), DefUnit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); - - unsigned Flags = llvm::DIType::FlagBlockByrefStruct; - - Ty = DebugFactory.CreateCompositeType(Tag, Unit, "", - llvm::DICompileUnit(), - 0, FieldOffset, 0, 0, Flags, - llvm::DIType(), Elements); - } + llvm::DICompileUnit Unit = getOrCreateCompileUnit(VD->getLocation()); + llvm::DIType Ty; + if (VD->hasAttr<BlocksAttr>()) + Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset); + else + Ty = getOrCreateType(VD->getType(), Unit); // Get location information. SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); + PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation()); unsigned Line = 0; if (!PLoc.isInvalid()) Line = PLoc.getLine(); else Unit = llvm::DICompileUnit(); - CharUnits offset = CGF->BlockDecls[Decl]; + CharUnits offset = CGF->BlockDecls[VD]; llvm::SmallVector<llvm::Value *, 9> addr; - llvm::LLVMContext &VMContext = CGM.getLLVMContext(); - addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - llvm::DIFactory::OpDeref)); - addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - llvm::DIFactory::OpPlus)); - addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset.getQuantity())); + const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext()); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpDeref)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpPlus)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); if (BDRE->isByRef()) { - addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - llvm::DIFactory::OpDeref)); - addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - llvm::DIFactory::OpPlus)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpDeref)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpPlus)); // offset of __forwarding field offset = CharUnits::fromQuantity(CGF->LLVMPointerWidth/8); - addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset.getQuantity())); - addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - llvm::DIFactory::OpDeref)); - addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - llvm::DIFactory::OpPlus)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpDeref)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpPlus)); // offset of x field offset = CharUnits::fromQuantity(XOffset/8); - addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset.getQuantity())); + addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); } // Create the descriptor for the variable. llvm::DIVariable D = - DebugFactory.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()), - Decl->getName(), Unit, Line, Ty, + DebugFactory.CreateComplexVariable(Tag, + llvm::DIDescriptor(RegionStack.back()), + VD->getName(), Unit, Line, Ty, addr); // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = - DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint()); + DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock()); llvm::DIScope DS(RegionStack.back()); llvm::DILocation DO(NULL); @@ -1542,10 +1623,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, Call->setMetadata("dbg", DL.getNode()); } -void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl, +void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder) { - EmitDeclare(Decl, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder); + EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder); } void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( @@ -1556,24 +1637,24 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument /// variable declaration. -void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, +void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, CGBuilderTy &Builder) { - EmitDeclare(Decl, llvm::dwarf::DW_TAG_arg_variable, AI, Builder); + EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, Builder); } /// EmitGlobalVariable - Emit information about a global variable. void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, - const VarDecl *Decl) { - + const VarDecl *D) { + // Create global variable debug descriptor. - llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); + llvm::DICompileUnit Unit = getOrCreateCompileUnit(D->getLocation()); SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); + PresumedLoc PLoc = SM.getPresumedLoc(D->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); - QualType T = Decl->getType(); + QualType T = D->getType(); if (T->isIncompleteArrayType()) { // CodeGen turns int[] into int[1] so we'll do the same here. @@ -1585,9 +1666,11 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - llvm::StringRef DeclName = Decl->getName(); - DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), DeclName, DeclName, - llvm::StringRef(), Unit, LineNo, + llvm::StringRef DeclName = D->getName(); + llvm::DIDescriptor DContext = + getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()), Unit); + DebugFactory.CreateGlobalVariable(DContext, DeclName, + DeclName, llvm::StringRef(), Unit, LineNo, getOrCreateType(T, Unit), Var->hasInternalLinkage(), true/*definition*/, Var); @@ -1595,16 +1678,16 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, /// EmitGlobalVariable - Emit information about an objective-c interface. void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, - ObjCInterfaceDecl *Decl) { + ObjCInterfaceDecl *ID) { // Create global variable debug descriptor. - llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); + llvm::DICompileUnit Unit = getOrCreateCompileUnit(ID->getLocation()); SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); + PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); - llvm::StringRef Name = Decl->getName(); + llvm::StringRef Name = ID->getName(); - QualType T = CGM.getContext().getObjCInterfaceType(Decl); + QualType T = CGM.getContext().getObjCInterfaceType(ID); if (T->isIncompleteArrayType()) { // CodeGen turns int[] into int[1] so we'll do the same here. @@ -1622,3 +1705,26 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, Var->hasInternalLinkage(), true/*definition*/, Var); } + +/// getOrCreateNamesSpace - Return namespace descriptor for the given +/// namespace decl. +llvm::DINameSpace +CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl, + llvm::DIDescriptor Unit) { + llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I = + NameSpaceCache.find(NSDecl); + if (I != NameSpaceCache.end()) + return llvm::DINameSpace(cast<llvm::MDNode>(I->second)); + + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(NSDecl->getLocation()); + unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); + + llvm::DIDescriptor Context = + getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()), Unit); + llvm::DINameSpace NS = + DebugFactory.CreateNameSpace(Context, NSDecl->getName(), + llvm::DICompileUnit(Unit.getNode()), LineNo); + NameSpaceCache[NSDecl] = llvm::WeakVH(NS.getNode()); + return NS; +} diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index fddd23b4e9c3..b2d3a1f1fa53 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -47,6 +47,8 @@ class CGDebugInfo { llvm::DIFactory DebugFactory; SourceLocation CurLoc, PrevLoc; + + llvm::DIType VTablePtrType; /// CompileUnitCache - Cache of previously constructed CompileUnits. llvm::DenseMap<unsigned, llvm::DICompileUnit> CompileUnitCache; @@ -59,12 +61,14 @@ class CGDebugInfo { llvm::DIType BlockLiteralGeneric; std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack; + llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap; - /// FunctionNames - This is a storage for function names that are + /// DebugInfoNames - This is a storage for names that are /// constructed on demand. For example, C++ destructors, C++ operators etc.. - llvm::BumpPtrAllocator FunctionNames; + llvm::BumpPtrAllocator DebugInfoNames; llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache; + llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache; /// Helper functions for getOrCreateType. llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U); @@ -83,16 +87,37 @@ class CGDebugInfo { llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DICompileUnit U); - + llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method, + llvm::DICompileUnit Unit); + llvm::DIType getOrCreateVTablePtrType(llvm::DICompileUnit Unit); + llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N, + llvm::DIDescriptor Unit); + llvm::DIType CreatePointerLikeType(unsigned Tag, const Type *Ty, QualType PointeeTy, llvm::DICompileUnit U); + + llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method, + llvm::DICompileUnit Unit, + llvm::DICompositeType &RecordTy); + void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, llvm::DICompileUnit U, llvm::SmallVectorImpl<llvm::DIDescriptor> &E, llvm::DICompositeType &T); + void CollectCXXBases(const CXXRecordDecl *Decl, + llvm::DICompileUnit Unit, + llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys, + llvm::DICompositeType &RecordTy); + + void CollectRecordFields(const RecordDecl *Decl, llvm::DICompileUnit U, llvm::SmallVectorImpl<llvm::DIDescriptor> &E); + + void CollectVtableInfo(const CXXRecordDecl *Decl, + llvm::DICompileUnit Unit, + llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys); + public: CGDebugInfo(CodeGenModule &CGM); ~CGDebugInfo(); @@ -150,8 +175,14 @@ private: void EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, llvm::Value *AI, CGBuilderTy &Builder, CodeGenFunction *CGF); - /// getContext - Get context info for the decl. - llvm::DIDescriptor getContext(const VarDecl *Decl,llvm::DIDescriptor &CU); + // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. + // See BuildByRefType. + llvm::DIType EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, + uint64_t *OffSet); + + /// getContextDescriptor - Get context info for the decl. + llvm::DIDescriptor getContextDescriptor(const Decl *Decl, + llvm::DIDescriptor &CU); /// getOrCreateCompileUnit - Get the compile unit from the cache or create a /// new one if necessary. @@ -168,6 +199,10 @@ private: /// name is constructred on demand (e.g. C++ destructor) then the name /// is stored on the side. llvm::StringRef getFunctionName(const FunctionDecl *FD); + + /// getVtableName - Get vtable name for the given Class. + llvm::StringRef getVtableName(const CXXRecordDecl *Decl); + }; } // namespace CodeGen } // namespace clang diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 9606a71527a4..793a22050677 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -76,8 +76,21 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { case VarDecl::Auto: case VarDecl::Register: return EmitLocalBlockVarDecl(D); - case VarDecl::Static: - return EmitStaticBlockVarDecl(D); + case VarDecl::Static: { + llvm::GlobalValue::LinkageTypes Linkage = + llvm::GlobalValue::InternalLinkage; + + // If this is a static declaration inside an inline function, it must have + // weak linkage so that the linker will merge multiple definitions of it. + if (getContext().getLangOptions().CPlusPlus) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl)) { + if (FD->isInlined()) + Linkage = llvm::GlobalValue::WeakAnyLinkage; + } + } + + return EmitStaticBlockVarDecl(D, Linkage); + } case VarDecl::Extern: case VarDecl::PrivateExtern: // Don't emit it now, allow it to be emitted lazily on its first use. @@ -120,7 +133,7 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, Ty.isConstant(getContext()), Linkage, CGM.EmitNullConstant(D.getType()), Name, 0, D.isThreadSpecified(), Ty.getAddressSpace()); - GV->setAlignment(getContext().getDeclAlignInBytes(&D)); + GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); return GV; } @@ -138,8 +151,13 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, if (!Init) { if (!getContext().getLangOptions().CPlusPlus) CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); - else + else { + // Since we have a static initializer, this global variable can't + // be constant. + GV->setConstant(false); + EmitStaticCXXBlockVarDeclInit(D, GV); + } return GV; } @@ -172,12 +190,12 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, return GV; } -void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { +void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, + llvm::GlobalValue::LinkageTypes Linkage) { llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); - llvm::GlobalVariable *GV = - CreateStaticBlockVarDecl(D, ".", llvm::GlobalValue::InternalLinkage); + llvm::GlobalVariable *GV = CreateStaticBlockVarDecl(D, ".", Linkage); // Store into LocalDeclMap before generating initializer to handle // circular references. @@ -281,8 +299,8 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) { } bool Packed = false; - unsigned Align = getContext().getDeclAlignInBytes(D); - if (Align > Target.getPointerAlign(0) / 8) { + CharUnits Align = getContext().getDeclAlign(D); + if (Align > CharUnits::fromQuantity(Target.getPointerAlign(0) / 8)) { // We have to insert padding. // The struct above has 2 32-bit integers. @@ -294,7 +312,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) { // Align the offset. unsigned AlignedOffsetInBytes = - llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align); + llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align.getQuantity()); unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes; if (NumPaddingBytes > 0) { @@ -334,7 +352,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { QualType Ty = D.getType(); bool isByRef = D.hasAttr<BlocksAttr>(); bool needsDispose = false; - unsigned Align = 0; + CharUnits Align = CharUnits::Zero(); bool IsSimpleConstantInitializer = false; llvm::Value *DeclPtr; @@ -350,7 +368,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // If this variable is marked 'const', emit the value as a global. if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstant(getContext())) { - EmitStaticBlockVarDecl(D); + EmitStaticBlockVarDecl(D, llvm::GlobalValue::InternalLinkage); return; } @@ -364,10 +382,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); Alloc->setName(D.getNameAsString()); - Align = getContext().getDeclAlignInBytes(&D); + Align = getContext().getDeclAlign(&D); if (isByRef) - Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8)); - Alloc->setAlignment(Align); + Align = std::max(Align, + CharUnits::fromQuantity(Target.getPointerAlign(0) / 8)); + Alloc->setAlignment(Align.getQuantity()); DeclPtr = Alloc; } else { // Targets that don't support recursion emit locals as globals. @@ -420,7 +439,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // Allocate memory for the array. llvm::AllocaInst *VLA = Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), VLASize, "vla"); - VLA->setAlignment(getContext().getDeclAlignInBytes(&D)); + VLA->setAlignment(getContext().getDeclAlign(&D).getQuantity()); DeclPtr = Builder.CreateBitCast(VLA, LElemPtrTy, "tmp"); } @@ -468,7 +487,8 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { assert(Init != 0 && "Wasn't a simple constant init?"); llvm::Value *AlignVal = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Align); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + Align.getQuantity()); const llvm::Type *IntPtr = llvm::IntegerType::get(VMContext, LLVMPointerWidth); llvm::Value *SizeVal = @@ -492,7 +512,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true, llvm::GlobalValue::InternalLinkage, Init, Name, 0, false, 0); - GV->setAlignment(Align); + GV->setAlignment(Align.getQuantity()); llvm::Value *SrcPtr = GV; if (SrcPtr->getType() != BP) @@ -501,7 +521,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal); } } else if (Ty->isReferenceType()) { - RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true); + RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true); EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); } else if (!hasAggregateLLVMType(Init->getType())) { llvm::Value *V = EmitScalarExpr(Init); @@ -554,19 +574,19 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const llvm::Type *V1; V1 = cast<llvm::PointerType>(DeclPtr->getType())->getElementType(); V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - (CGM.getTargetData().getTypeStoreSizeInBits(V1) - / 8)); + CGM.GetTargetTypeStoreSize(V1).getQuantity()); Builder.CreateStore(V, size_field); if (flags & BLOCK_HAS_COPY_DISPOSE) { BlockHasCopyDispose = true; llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4); - Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag, Align), + Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag, + Align.getQuantity()), copy_helper); llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5); Builder.CreateStore(BuildbyrefDestroyHelper(DeclPtr->getType(), flag, - Align), + Align.getQuantity()), destroy_helper); } } @@ -683,25 +703,18 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { CanQualType CTy = getContext().getCanonicalType(Ty); llvm::Value *DeclPtr; - if (!Ty->isConstantSizeType()) { - // Variable sized values always are passed by-reference. + // If this is an aggregate or variable sized value, reuse the input pointer. + if (!Ty->isConstantSizeType() || + CodeGenFunction::hasAggregateLLVMType(Ty)) { DeclPtr = Arg; } else { - // A fixed sized single-value variable becomes an alloca in the entry block. - const llvm::Type *LTy = ConvertTypeForMem(Ty); - if (LTy->isSingleValueType()) { - // TODO: Alignment - DeclPtr = CreateTempAlloca(LTy); - DeclPtr->setName(D.getNameAsString() + llvm::StringRef(".addr")); - - // Store the initial value into the alloca. - EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty); - } else { - // Otherwise, if this is an aggregate, just use the input pointer. - DeclPtr = Arg; - } - Arg->setName(D.getNameAsString()); + // Otherwise, create a temporary to hold the value. + DeclPtr = CreateMemTemp(Ty, D.getName() + ".addr"); + + // Store the initial value into the alloca. + EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty); } + Arg->setName(D.getName()); llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 47773a0d69e3..0de3b0be4b1a 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -80,8 +80,13 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, EmitDeclInit(*this, D, DeclPtr); return; } - - ErrorUnsupported(Init, "global variable that binds to a reference"); + if (Init->isLvalue(getContext()) == Expr::LV_Valid) { + RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true); + EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T); + return; + } + ErrorUnsupported(Init, + "global variable that binds reference to a non-lvalue"); } void @@ -179,57 +184,120 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, FinishFunction(); } +static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) { + // int __cxa_guard_acquire(__int64_t *guard_object); + + const llvm::Type *Int64PtrTy = + llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); + + std::vector<const llvm::Type*> Args(1, Int64PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(CGF.ConvertType(CGF.getContext().IntTy), + Args, /*isVarArg=*/false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire"); +} + +static llvm::Constant *getGuardReleaseFn(CodeGenFunction &CGF) { + // void __cxa_guard_release(__int64_t *guard_object); + + const llvm::Type *Int64PtrTy = + llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); + + std::vector<const llvm::Type*> Args(1, Int64PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, /*isVarArg=*/false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release"); +} + +static llvm::Constant *getGuardAbortFn(CodeGenFunction &CGF) { + // void __cxa_guard_abort(__int64_t *guard_object); + + const llvm::Type *Int64PtrTy = + llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); + + std::vector<const llvm::Type*> Args(1, Int64PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, /*isVarArg=*/false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort"); +} + void CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, llvm::GlobalVariable *GV) { - // FIXME: This should use __cxa_guard_{acquire,release}? - - assert(!getContext().getLangOptions().ThreadsafeStatics && - "thread safe statics are currently not supported!"); - + bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics; + llvm::SmallString<256> GuardVName; CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); // Create the guard variable. - llvm::GlobalValue *GuardV = - new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), + const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(VMContext); + llvm::GlobalValue *GuardVariable = + new llvm::GlobalVariable(CGM.getModule(), Int64Ty, false, GV->getLinkage(), - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), + llvm::Constant::getNullValue(Int64Ty), GuardVName.str()); // Load the first byte of the guard variable. const llvm::Type *PtrTy = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), - "tmp"); - - // Compare it against 0. - llvm::Value *nullValue - = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); - llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); + llvm::Value *V = + Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp"); - llvm::BasicBlock *InitBlock = createBasicBlock("init"); + llvm::BasicBlock *InitCheckBlock = createBasicBlock("init.check"); llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); - // If the guard variable is 0, jump to the initializer code. - Builder.CreateCondBr(ICmp, InitBlock, EndBlock); + // Check if the first byte of the guard variable is zero. + Builder.CreateCondBr(Builder.CreateIsNull(V, "tobool"), + InitCheckBlock, EndBlock); - EmitBlock(InitBlock); + EmitBlock(InitCheckBlock); + + if (ThreadsafeStatics) { + // Call __cxa_guard_acquire. + V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable); + + llvm::BasicBlock *InitBlock = createBasicBlock("init"); + + Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"), + InitBlock, EndBlock); + + EmitBlock(InitBlock); + + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + + // Call __cxa_guard_abort. + Builder.CreateCall(getGuardAbortFn(*this), GuardVariable); + } + } if (D.getType()->isReferenceType()) { QualType T = D.getType(); // We don't want to pass true for IsInitializer here, because a static // reference to a temporary does not extend its lifetime. - RValue RV = EmitReferenceBindingToExpr(D.getInit(), T, + RValue RV = EmitReferenceBindingToExpr(D.getInit(), /*IsInitializer=*/false); EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T); } else EmitDeclInit(*this, D, GV); - Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), - 1), - Builder.CreateBitCast(GuardV, PtrTy)); + if (ThreadsafeStatics) { + // Call __cxa_guard_release. + Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable); + } else { + llvm::Value *One = + llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1); + Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy)); + } EmitBlock(EndBlock); } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index bd0461fd2808..d956c1c3cd85 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -100,10 +100,6 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); } -// FIXME: Eventually this will all go into the backend. Set from the target for -// now. -static int using_sjlj_exceptions = 0; - static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector<const llvm::Type*> Args(1, Int8PtrTy); @@ -112,7 +108,7 @@ static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, false); - if (using_sjlj_exceptions) + if (CGF.CGM.getLangOptions().SjLjExceptions) return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); } @@ -194,9 +190,9 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), CopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - CopyCtor->getType()->getAs<FunctionType>()->getResultType(); - CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + const FunctionProtoType *FPT + = CopyCtor->getType()->getAs<FunctionProtoType>(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, CopyCtor); CGF.setInvokeDest(PrevLandingPad); } else @@ -244,9 +240,10 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), CopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - CopyCtor->getType()->getAs<FunctionType>()->getResultType(); - CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + + const FunctionProtoType *FPT + = CopyCtor->getType()->getAs<FunctionProtoType>(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, CopyCtor); } else llvm_unreachable("uncopyable object"); @@ -316,6 +313,9 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { } void CodeGenFunction::EmitStartEHSpec(const Decl *D) { + if (!Exceptions) + return; + const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); if (FD == 0) return; @@ -410,6 +410,9 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { } void CodeGenFunction::EmitEndEHSpec(const Decl *D) { + if (!Exceptions) + return; + const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); if (FD == 0) return; @@ -466,6 +469,7 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); PushCleanupBlock(DtorEpilogue); + InitializeVtablePtrs(DD->getParent()); EmitStmt(S.getTryBlock()); CleanupBlockInfo Info = PopCleanupBlock(); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2358bb35923a..830954fd10cc 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -36,16 +36,24 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); } +llvm::Value *CodeGenFunction::CreateMemTemp(QualType Ty, const llvm::Twine &Name) { + llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty), Name); + // FIXME: Should we prefer the preferred type alignment here? + CharUnits Align = getContext().getTypeAlignInChars(Ty); + Alloc->setAlignment(Align.getQuantity()); + return Alloc; +} + /// EvaluateExprAsBool - Perform the usual unary conversions on the specified /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { QualType BoolTy = getContext().BoolTy; if (E->getType()->isMemberFunctionPointerType()) { - llvm::Value *Ptr = CreateTempAlloca(ConvertType(E->getType())); - EmitAggExpr(E, Ptr, /*VolatileDest=*/false); + LValue LV = EmitAggExprToLValue(E); // Get the pointer. - llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr"); + llvm::Value *FuncPtr = Builder.CreateStructGEP(LV.getAddress(), 0, + "src.ptr"); FuncPtr = Builder.CreateLoad(FuncPtr); llvm::Value *IsNotNull = @@ -87,13 +95,12 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, if (hasAggregateLLVMType(E->getType()) && !E->getType()->isAnyComplexType()) - AggLoc = CreateTempAlloca(ConvertType(E->getType()), "agg.tmp"); + AggLoc = CreateMemTemp(E->getType(), "agg.tmp"); return EmitAnyExpr(E, AggLoc, IsAggLocVolatile, /*IgnoreResult=*/false, IsInitializer); } RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, - QualType DestType, bool IsInitializer) { bool ShouldDestroyTemporaries = false; unsigned OldNumLiveTemporaries = 0; @@ -114,8 +121,16 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (E->isLvalue(getContext()) == Expr::LV_Valid) { // Emit the expr as an lvalue. LValue LV = EmitLValue(E); - if (LV.isSimple()) + if (LV.isSimple()) { + if (ShouldDestroyTemporaries) { + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + } + return RValue::get(LV.getAddress()); + } + Val = EmitLoadOfLValue(LV, E->getType()); if (ShouldDestroyTemporaries) { @@ -188,8 +203,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, Val = RValue::get(Val.getAggregateAddr()); } else { // Create a temporary variable that we can bind the reference to. - llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), - "reftmp"); + llvm::Value *Temp = CreateMemTemp(E->getType(), "reftmp"); if (Val.isScalar()) EmitStoreOfScalar(Val.getScalarVal(), Temp, false, E->getType()); else @@ -546,6 +560,8 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { cast<llvm::PointerType>(Ptr->getType())->getElementType(); // Simple scalar l-value. + // + // FIXME: We shouldn't have to use isSingleValueType here. if (EltTy->isSingleValueType()) return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(), ExprType)); @@ -1069,9 +1085,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) return EmitFunctionDeclLValue(*this, E, FD); + // FIXME: the qualifier check does not seem sufficient here if (E->getQualifier()) { - // FIXME: the qualifier check does not seem sufficient here - return EmitPointerToDataMemberLValue(cast<FieldDecl>(ND)); + const FieldDecl *FD = cast<FieldDecl>(ND); + llvm::Value *V = CGM.EmitPointerToDataMember(FD); + + return LValue::MakeAddr(V, MakeQualifiers(FD->getType())); } assert(false && "Unhandled DeclRefExpr"); @@ -1166,8 +1185,7 @@ LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) { GlobalVarName += FnName; std::string FunctionName = - PredefinedExpr::ComputeName(getContext(), (PredefinedExpr::IdentType)Type, - CurCodeDecl); + PredefinedExpr::ComputeName((PredefinedExpr::IdentType)Type, CurCodeDecl); llvm::Constant *C = CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str()); @@ -1350,7 +1368,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { llvm::Value *Vec = EmitScalarExpr(E->getBase()); // Store the vector to memory (because LValue wants an address). - llvm::Value *VecMem =CreateTempAlloca(ConvertType(E->getBase()->getType())); + llvm::Value *VecMem = CreateMemTemp(E->getBase()->getType()); Builder.CreateStore(Vec, VecMem); Base = LValue::MakeAddr(VecMem, Qualifiers()); } @@ -1381,7 +1399,6 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { } LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { - bool isUnion = false; bool isNonGC = false; Expr *BaseExpr = E->getBase(); llvm::Value *BaseValue = NULL; @@ -1392,16 +1409,12 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { BaseValue = EmitScalarExpr(BaseExpr); const PointerType *PTy = BaseExpr->getType()->getAs<PointerType>(); - if (PTy->getPointeeType()->isUnionType()) - isUnion = true; BaseQuals = PTy->getPointeeType().getQualifiers(); } else if (isa<ObjCPropertyRefExpr>(BaseExpr->IgnoreParens()) || isa<ObjCImplicitSetterGetterRefExpr>( BaseExpr->IgnoreParens())) { RValue RV = EmitObjCPropertyGet(BaseExpr); BaseValue = RV.getAggregateAddr(); - if (BaseExpr->getType()->isUnionType()) - isUnion = true; BaseQuals = BaseExpr->getType().getQualifiers(); } else { LValue BaseLV = EmitLValue(BaseExpr); @@ -1410,14 +1423,12 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { // FIXME: this isn't right for bitfields. BaseValue = BaseLV.getAddress(); QualType BaseTy = BaseExpr->getType(); - if (BaseTy->isUnionType()) - isUnion = true; BaseQuals = BaseTy.getQualifiers(); } NamedDecl *ND = E->getMemberDecl(); if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) { - LValue LV = EmitLValueForField(BaseValue, Field, isUnion, + LValue LV = EmitLValueForField(BaseValue, Field, BaseQuals.getCVRQualifiers()); LValue::SetObjCNonGC(LV, isNonGC); setObjCGCLValueClass(getContext(), E, LV); @@ -1461,7 +1472,6 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, const FieldDecl* Field, - bool isUnion, unsigned CVRQualifiers) { if (Field->isBitField()) return EmitLValueForBitfield(BaseValue, Field, CVRQualifiers); @@ -1470,7 +1480,7 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp"); // Match union field type. - if (isUnion) { + if (Field->getParent()->isUnion()) { const llvm::Type *FieldTy = CGM.getTypes().ConvertTypeForMem(Field->getType()); const llvm::PointerType * BaseTy = @@ -1492,9 +1502,26 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, return LValue::MakeAddr(V, Quals); } +LValue +CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value* BaseValue, + const FieldDecl* Field, + unsigned CVRQualifiers) { + QualType FieldType = Field->getType(); + + if (!FieldType->isReferenceType()) + return EmitLValueForField(BaseValue, Field, CVRQualifiers); + + unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); + llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp"); + + assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); + + return LValue::MakeAddr(V, MakeQualifiers(FieldType)); +} + LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ - const llvm::Type *LTy = ConvertType(E->getType()); - llvm::Value *DeclPtr = CreateTempAlloca(LTy, ".compoundliteral"); + llvm::Value *DeclPtr = CreateTempAlloca(ConvertTypeForMem(E->getType()), + ".compoundliteral"); const Expr* InitExpr = E->getInitializer(); LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); @@ -1527,18 +1554,25 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); + // Any temporaries created here are conditional. + BeginConditionalBranch(); EmitBlock(LHSBlock); - LValue LHS = EmitLValue(E->getLHS()); + EndConditionalBranch(); + if (!LHS.isSimple()) return EmitUnsupportedLValue(E, "conditional operator"); + // FIXME: We shouldn't need an alloca for this. llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(),"condtmp"); Builder.CreateStore(LHS.getAddress(), Temp); EmitBranch(ContBlock); + // Any temporaries created here are conditional. + BeginConditionalBranch(); EmitBlock(RHSBlock); LValue RHS = EmitLValue(E->getRHS()); + EndConditionalBranch(); if (!RHS.isSimple()) return EmitUnsupportedLValue(E, "conditional operator"); @@ -1556,10 +1590,7 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { !E->getType()->isAnyComplexType()) && "Unexpected conditional operator!"); - llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); - EmitAggExpr(E, Temp, false); - - return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); + return EmitAggExprToLValue(E); } /// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast. @@ -1606,12 +1637,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { return LValue::MakeAddr(Base, MakeQualifiers(E->getType())); } - case CastExpr::CK_ToUnion: { - llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); - EmitAnyExpr(E->getSubExpr(), Temp, false); - - return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); - } + case CastExpr::CK_ToUnion: + return EmitAggExprToLValue(E); case CastExpr::CK_BaseToDerived: { const RecordType *BaseClassTy = E->getSubExpr()->getType()->getAs<RecordType>(); @@ -1646,13 +1673,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { LValue CodeGenFunction::EmitNullInitializationLValue( const CXXZeroInitValueExpr *E) { QualType Ty = E->getType(); - const llvm::Type *LTy = ConvertTypeForMem(Ty); - llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); - unsigned Align = getContext().getTypeAlign(Ty)/8; - Alloc->setAlignment(Align); - LValue lvalue = LValue::MakeAddr(Alloc, Qualifiers()); - EmitMemSetToZero(lvalue.getAddress(), Ty); - return lvalue; + LValue LV = LValue::MakeAddr(CreateMemTemp(Ty), MakeQualifiers(Ty)); + EmitMemSetToZero(LV.getAddress(), Ty); + return LV; } //===--------------------------------------------------------------------===// @@ -1725,10 +1748,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { return LV; } - llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); - EmitAggExpr(E, Temp, false); - // FIXME: Are these qualifiers correct? - return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); + return EmitAggExprToLValue(E); } LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { @@ -1746,13 +1766,11 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { // FIXME: This shouldn't require another copy. - llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); - EmitAggExpr(E, Temp, false); - return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); + return EmitAggExprToLValue(E); } LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { - llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp"); + llvm::Value *Temp = CreateMemTemp(E->getType(), "tmp"); EmitCXXConstructExpr(Temp, E); return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } @@ -1840,21 +1858,6 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); } - -LValue CodeGenFunction::EmitPointerToDataMemberLValue(const FieldDecl *Field) { - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Field->getDeclContext()); - QualType NNSpecTy = - getContext().getCanonicalType( - getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(ClassDecl))); - NNSpecTy = getContext().getPointerType(NNSpecTy); - llvm::Value *V = llvm::Constant::getNullValue(ConvertType(NNSpecTy)); - LValue MemExpLV = EmitLValueForField(V, Field, /*isUnion=*/false, - /*Qualifiers=*/0); - const llvm::Type *ResultType = ConvertType(getContext().getPointerDiffType()); - V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, "datamember"); - return LValue::MakeAddr(V, MakeQualifiers(Field->getType())); -} - RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, ReturnValueSlot ReturnValue, CallExpr::const_arg_iterator ArgBeg, @@ -1867,20 +1870,14 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, CalleeType = getContext().getCanonicalType(CalleeType); - QualType FnType = cast<PointerType>(CalleeType)->getPointeeType(); - QualType ResultType = cast<FunctionType>(FnType)->getResultType(); + const FunctionType *FnType + = cast<FunctionType>(cast<PointerType>(CalleeType)->getPointeeType()); + QualType ResultType = FnType->getResultType(); CallArgList Args; EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd); - // FIXME: We should not need to do this, it should be part of the function - // type. - unsigned CallingConvention = 0; - if (const llvm::Function *F = - dyn_cast<llvm::Function>(Callee->stripPointerCasts())) - CallingConvention = F->getCallingConv(); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args, - CallingConvention), + return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType), Callee, ReturnValue, Args, TargetDecl); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index c852d65b859f..97455c7b13cf 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -118,7 +118,7 @@ public: void VisitVAArgExpr(VAArgExpr *E); - void EmitInitializationToLValue(Expr *E, LValue Address); + void EmitInitializationToLValue(Expr *E, LValue Address, QualType T); void EmitNullInitializationToLValue(LValue Address, QualType T); // case Expr::ChooseExprClass: void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); } @@ -147,7 +147,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { return; // If the source is volatile, we must read from it; to do that, we need // some place to put it. - DestPtr = CGF.CreateTempAlloca(CGF.ConvertType(E->getType()), "agg.tmp"); + DestPtr = CGF.CreateMemTemp(E->getType(), "agg.tmp"); } if (RequiresGCollection) { @@ -188,7 +188,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr, CGF.ConvertType(PtrTy)); EmitInitializationToLValue(E->getSubExpr(), - LValue::MakeAddr(CastPtr, Qualifiers())); + LValue::MakeAddr(CastPtr, Qualifiers()), + E->getType()); break; } @@ -227,8 +228,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CastExpr::CK_BaseToDerivedMemberPointer: { QualType SrcType = E->getSubExpr()->getType(); - llvm::Value *Src = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(SrcType), - "tmp"); + llvm::Value *Src = CGF.CreateMemTemp(SrcType, "tmp"); CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified()); llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr"); @@ -252,8 +252,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) std::swap(DerivedDecl, BaseDecl); - llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl); - if (Adj) { + if (llvm::Constant *Adj = + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) { if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); else @@ -326,10 +326,18 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { int64_t Index = CGF.CGM.getVtableInfo().getMethodVtableIndex(MD); - FuncPtr = llvm::ConstantInt::get(PtrDiffTy, Index + 1); + // Itanium C++ ABI 2.3: + // For a non-virtual function, this field is a simple function pointer. + // For a virtual function, it is 1 plus the virtual table offset + // (in bytes) of the function, represented as a ptrdiff_t. + FuncPtr = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); } else { - FuncPtr = llvm::ConstantExpr::getPtrToInt(CGF.CGM.GetAddrOfFunction(MD), - PtrDiffTy); + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *Ty = + CGF.CGM.getTypes().GetFunctionType(CGF.CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Fn = CGF.CGM.GetAddrOfFunction(MD, Ty); + FuncPtr = llvm::ConstantExpr::getPtrToInt(Fn, PtrDiffTy); } Builder.CreateStore(FuncPtr, DstPtr, VolatileDest); @@ -371,14 +379,14 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { if (LHS.isPropertyRef()) { llvm::Value *AggLoc = DestPtr; if (!AggLoc) - AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType())); + AggLoc = CGF.CreateMemTemp(E->getRHS()->getType()); CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest); CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), RValue::getAggregate(AggLoc, VolatileDest)); } else if (LHS.isKVCRef()) { llvm::Value *AggLoc = DestPtr; if (!AggLoc) - AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType())); + AggLoc = CGF.CreateMemTemp(E->getRHS()->getType()); CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest); CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(), RValue::getAggregate(AggLoc, VolatileDest)); @@ -408,21 +416,21 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) { CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); - CGF.StartConditionalBranch(); + CGF.BeginConditionalBranch(); CGF.EmitBlock(LHSBlock); // Handle the GNU extension for missing LHS. assert(E->getLHS() && "Must have LHS for aggregate value"); Visit(E->getLHS()); - CGF.FinishConditionalBranch(); + CGF.EndConditionalBranch(); CGF.EmitBranch(ContBlock); - CGF.StartConditionalBranch(); + CGF.BeginConditionalBranch(); CGF.EmitBlock(RHSBlock); Visit(E->getRHS()); - CGF.FinishConditionalBranch(); + CGF.EndConditionalBranch(); CGF.EmitBranch(ContBlock); CGF.EmitBlock(ContBlock); @@ -449,7 +457,7 @@ void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { if (!Val) { // Create a temporary variable. - Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); + Val = CGF.CreateMemTemp(E->getType(), "tmp"); // FIXME: volatile CGF.EmitAggExpr(E->getSubExpr(), Val, false); @@ -467,7 +475,7 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) { if (!Val) { // Create a temporary variable. - Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); + Val = CGF.CreateMemTemp(E->getType(), "tmp"); } if (E->requiresZeroInitialization()) @@ -484,7 +492,7 @@ void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { if (!Val) { // Create a temporary variable. - Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); + Val = CGF.CreateMemTemp(E->getType(), "tmp"); } CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer); } @@ -494,7 +502,7 @@ void AggExprEmitter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { if (!Val) { // Create a temporary variable. - Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); + Val = CGF.CreateMemTemp(E->getType(), "tmp"); } LValue LV = LValue::MakeAddr(Val, Qualifiers()); EmitNullInitializationToLValue(LV, E->getType()); @@ -505,23 +513,27 @@ void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { if (!Val) { // Create a temporary variable. - Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); + Val = CGF.CreateMemTemp(E->getType(), "tmp"); } LValue LV = LValue::MakeAddr(Val, Qualifiers()); EmitNullInitializationToLValue(LV, E->getType()); } -void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) { +void +AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV, QualType T) { // FIXME: Ignore result? // FIXME: Are initializers affected by volatile? if (isa<ImplicitValueInitExpr>(E)) { - EmitNullInitializationToLValue(LV, E->getType()); - } else if (E->getType()->isComplexType()) { + EmitNullInitializationToLValue(LV, T); + } else if (T->isReferenceType()) { + RValue RV = CGF.EmitReferenceBindingToExpr(E, /*IsInitializer=*/false); + CGF.EmitStoreThroughLValue(RV, LV, T); + } else if (T->isAnyComplexType()) { CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false); - } else if (CGF.hasAggregateLLVMType(E->getType())) { + } else if (CGF.hasAggregateLLVMType(T)) { CGF.EmitAnyExpr(E, LV.getAddress(), false); } else { - CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(E), LV, E->getType()); + CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(E), LV, T); } } @@ -590,7 +602,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array"); if (i < NumInitElements) EmitInitializationToLValue(E->getInit(i), - LValue::MakeAddr(NextVal, Quals)); + LValue::MakeAddr(NextVal, Quals), + ElementType); else EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, Quals), ElementType); @@ -627,11 +640,11 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // FIXME: volatility FieldDecl *Field = E->getInitializedFieldInUnion(); - LValue FieldLoc = CGF.EmitLValueForField(DestPtr, Field, true, 0); + LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, Field, 0); if (NumInitElements) { // Store the initializer into the field - EmitInitializationToLValue(E->getInit(0), FieldLoc); + EmitInitializationToLValue(E->getInit(0), FieldLoc, Field->getType()); } else { // Default-initialize to null EmitNullInitializationToLValue(FieldLoc, Field->getType()); @@ -653,12 +666,13 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { continue; // FIXME: volatility - LValue FieldLoc = CGF.EmitLValueForField(DestPtr, *Field, false, 0); + LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, *Field, 0); // We never generate write-barries for initialized fields. LValue::SetObjCNonGC(FieldLoc, true); if (CurInitVal < NumInitElements) { // Store the initializer into the field - EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc); + EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc, + Field->getType()); } else { // We're out of initalizers; default-initialize to null EmitNullInitializationToLValue(FieldLoc, Field->getType()); @@ -674,6 +688,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { /// type. The result is computed into DestPtr. Note that if DestPtr is null, /// the value of the aggregate expression is not needed. If VolatileDest is /// true, DestPtr cannot be 0. +// +// FIXME: Take Qualifiers object. void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr, bool VolatileDest, bool IgnoreResult, bool IsInitializer, @@ -688,6 +704,14 @@ void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr, .Visit(const_cast<Expr*>(E)); } +LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) { + assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!"); + Qualifiers Q = MakeQualifiers(E->getType()); + llvm::Value *Temp = CreateMemTemp(E->getType()); + EmitAggExpr(E, Temp, Q.hasVolatile()); + return LValue::MakeAddr(Temp, Q); +} + void CodeGenFunction::EmitAggregateClear(llvm::Value *DestPtr, QualType Ty) { assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index e264109f02f0..032862160464 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -42,8 +42,10 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, // And the rest of the call args EmitCallArgs(Args, FPT, ArgBeg, ArgEnd); - QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, + QualType ResultType = FPT->getResultType(); + return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args, + FPT->getCallConv(), + FPT->getNoReturnAttr()), Callee, ReturnValue, Args, MD); } @@ -60,7 +62,7 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { } // We can always devirtualize calls on temporary object expressions. - if (isa<CXXTemporaryObjectExpr>(Base)) + if (isa<CXXConstructExpr>(Base)) return true; // And calls on bound temporaries. @@ -159,12 +161,10 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), FPT->isVariadic()); - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); // Get the member function pointer. - llvm::Value *MemFnPtr = - CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn"); + llvm::Value *MemFnPtr = CreateMemTemp(MemFnExpr->getType(), "mem.fn"); EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false); // Emit the 'this' pointer. @@ -206,19 +206,20 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); EmitBlock(FnVirtual); - const llvm::Type *VTableTy = - FTy->getPointerTo()->getPointerTo()->getPointerTo(); + const llvm::Type *VtableTy = + FTy->getPointerTo()->getPointerTo(); - llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy); - VTable = Builder.CreateLoad(VTable); + llvm::Value *Vtable = Builder.CreateBitCast(This, VtableTy->getPointerTo()); + Vtable = Builder.CreateLoad(Vtable); - VTable = Builder.CreateGEP(VTable, FnAsInt, "fn"); + Vtable = Builder.CreateBitCast(Vtable, Int8PtrTy); + llvm::Value *VtableOffset = + Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1)); - // Since the function pointer is 1 plus the virtual table offset, we - // subtract 1 by using a GEP. - VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1); + Vtable = Builder.CreateGEP(Vtable, VtableOffset, "fn"); + Vtable = Builder.CreateBitCast(Vtable, VtableTy); - llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); + llvm::Value *VirtualFn = Builder.CreateLoad(Vtable, "virtualfn"); EmitBranch(FnEnd); EmitBlock(FnNonVirtual); @@ -244,8 +245,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, // And the rest of the call args EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end()); - QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType(); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, + const FunctionType *BO_FPT = BO->getType()->getAs<FunctionProtoType>(); + return EmitCall(CGM.getTypes().getFunctionInfo(Args, BO_FPT), Callee, ReturnValue, Args); } @@ -339,18 +340,20 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, } else // Call the constructor. - EmitCXXConstructorCall(CD, Ctor_Complete, Dest, + EmitCXXConstructorCall(CD, + E->isBaseInitialization()? Ctor_Base : Ctor_Complete, + Dest, E->arg_begin(), E->arg_end()); } -static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { +static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { const RecordType *RT = ElementType->getAs<RecordType>(); if (!RT) - return 0; + return CharUnits::Zero(); const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); if (!RD) - return 0; + return CharUnits::Zero(); // Check if the class has a trivial destructor. if (RD->hasTrivialDestructor()) { @@ -372,25 +375,25 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { // No usual deallocation function, we don't need a cookie. if (!UsualDeallocationFunction) - return 0; + return CharUnits::Zero(); // The usual deallocation function doesn't take a size_t argument, so we // don't need a cookie. if (UsualDeallocationFunction->getNumParams() == 1) - return 0; + return CharUnits::Zero(); assert(UsualDeallocationFunction->getNumParams() == 2 && "Unexpected deallocation function type!"); } // Padding is the maximum of sizeof(size_t) and alignof(ElementType) - return std::max(Ctx.getTypeSize(Ctx.getSizeType()), - static_cast<uint64_t>(Ctx.getTypeAlign(ElementType))) / 8; + return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()), + Ctx.getTypeAlignInChars(ElementType)); } -static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { +static CharUnits CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { if (!E->isArray()) - return 0; + return CharUnits::Zero(); // No cookie is required if the new operator being used is // ::operator new[](size_t, void*). @@ -401,7 +404,7 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { Ctx.getCanonicalType(OperatorNew->getParamDecl(1)->getType()); if (ParamType == Ctx.VoidPtrTy) - return 0; + return CharUnits::Zero(); } } @@ -412,25 +415,25 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, const CXXNewExpr *E, llvm::Value *& NumElements) { QualType Type = E->getAllocatedType(); - uint64_t TypeSizeInBytes = CGF.getContext().getTypeSize(Type) / 8; + CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(Type); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); if (!E->isArray()) - return llvm::ConstantInt::get(SizeTy, TypeSizeInBytes); + return llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity()); - uint64_t CookiePadding = CalculateCookiePadding(CGF.getContext(), E); + CharUnits CookiePadding = CalculateCookiePadding(CGF.getContext(), E); Expr::EvalResult Result; if (E->getArraySize()->Evaluate(Result, CGF.getContext()) && !Result.HasSideEffects && Result.Val.isInt()) { - uint64_t AllocSize = - Result.Val.getInt().getZExtValue() * TypeSizeInBytes + CookiePadding; + CharUnits AllocSize = + Result.Val.getInt().getZExtValue() * TypeSize + CookiePadding; NumElements = llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue()); - return llvm::ConstantInt::get(SizeTy, AllocSize); + return llvm::ConstantInt::get(SizeTy, AllocSize.getQuantity()); } // Emit the array size expression. @@ -439,11 +442,13 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, // Multiply with the type size. llvm::Value *V = CGF.Builder.CreateMul(NumElements, - llvm::ConstantInt::get(SizeTy, TypeSizeInBytes)); + llvm::ConstantInt::get(SizeTy, + TypeSize.getQuantity())); // And add the cookie padding if necessary. - if (CookiePadding) - V = CGF.Builder.CreateAdd(V, llvm::ConstantInt::get(SizeTy, CookiePadding)); + if (!CookiePadding.isZero()) + V = CGF.Builder.CreateAdd(V, + llvm::ConstantInt::get(SizeTy, CookiePadding.getQuantity())); return V; } @@ -538,7 +543,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // Emit the call to new. RValue RV = - EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs), + EmitCall(CGM.getTypes().getFunctionInfo(NewArgs, NewFTy), CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD); // If an allocation function is declared with an empty exception specification @@ -567,20 +572,22 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { Builder.CreateCondBr(IsNull, NewNull, NewNotNull); EmitBlock(NewNotNull); } - - if (uint64_t CookiePadding = CalculateCookiePadding(getContext(), E)) { - uint64_t CookieOffset = - CookiePadding - getContext().getTypeSize(SizeTy) / 8; + + CharUnits CookiePadding = CalculateCookiePadding(getContext(), E); + if (!CookiePadding.isZero()) { + CharUnits CookieOffset = + CookiePadding - getContext().getTypeSizeInChars(SizeTy); llvm::Value *NumElementsPtr = - Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset); + Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset.getQuantity()); NumElementsPtr = Builder.CreateBitCast(NumElementsPtr, ConvertType(SizeTy)->getPointerTo()); Builder.CreateStore(NumElements, NumElementsPtr); // Now add the padding to the new ptr. - NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr, CookiePadding); + NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr, + CookiePadding.getQuantity()); } NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); @@ -611,23 +618,24 @@ GetAllocatedObjectPtrAndNumElements(CodeGenFunction &CGF, QualType SizeTy = CGF.getContext().getSizeType(); const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); - uint64_t DeleteTypeAlign = CGF.getContext().getTypeAlign(DeleteTy); - uint64_t CookiePadding = std::max(CGF.getContext().getTypeSize(SizeTy), - DeleteTypeAlign) / 8; - assert(CookiePadding && "CookiePadding should not be 0."); + CharUnits DeleteTypeAlign = CGF.getContext().getTypeAlignInChars(DeleteTy); + CharUnits CookiePadding = + std::max(CGF.getContext().getTypeSizeInChars(SizeTy), + DeleteTypeAlign); + assert(!CookiePadding.isZero() && "CookiePadding should not be 0."); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - uint64_t CookieOffset = - CookiePadding - CGF.getContext().getTypeSize(SizeTy) / 8; + CharUnits CookieOffset = + CookiePadding - CGF.getContext().getTypeSizeInChars(SizeTy); llvm::Value *AllocatedObjectPtr = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); AllocatedObjectPtr = CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, - -CookiePadding); + -CookiePadding.getQuantity()); llvm::Value *NumElementsPtr = CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, - CookieOffset); + CookieOffset.getQuantity()); NumElementsPtr = CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo()); @@ -651,13 +659,13 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, QualType SizeTy; if (DeleteFTy->getNumArgs() == 2) { SizeTy = DeleteFTy->getArgType(1); - uint64_t DeleteTypeSize = getContext().getTypeSize(DeleteTy) / 8; - Size = llvm::ConstantInt::get(ConvertType(SizeTy), DeleteTypeSize); + CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy); + Size = llvm::ConstantInt::get(ConvertType(SizeTy), + DeleteTypeSize.getQuantity()); } if (DeleteFD->getOverloadedOperator() == OO_Array_Delete && - - CalculateCookiePadding(getContext(), DeleteTy)) { + !CalculateCookiePadding(getContext(), DeleteTy).isZero()) { // We need to get the number of elements in the array from the cookie. llvm::Value *AllocatedObjectPtr; llvm::Value *NumElements; @@ -679,8 +687,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy)); // Emit the call to delete. - EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), - DeleteArgs), + EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy), CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(), DeleteArgs, DeleteFD); } diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 5ec336ce79e9..591534042f51 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -366,7 +366,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { ComplexPairTy Op = Visit(E->getSubExpr()); llvm::Value *ResR, *ResI; - if (Op.first->getType()->isFloatingPoint()) { + if (Op.first->getType()->isFloatingPointTy()) { ResR = Builder.CreateFNeg(Op.first, "neg.r"); ResI = Builder.CreateFNeg(Op.second, "neg.i"); } else { @@ -384,7 +384,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) { // ~(a+ib) = a + i*-b ComplexPairTy Op = Visit(E->getSubExpr()); llvm::Value *ResI; - if (Op.second->getType()->isFloatingPoint()) + if (Op.second->getType()->isFloatingPointTy()) ResI = Builder.CreateFNeg(Op.second, "conj.i"); else ResI = Builder.CreateNeg(Op.second, "conj.i"); @@ -395,7 +395,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) { ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) { llvm::Value *ResR, *ResI; - if (Op.LHS.first->getType()->isFloatingPoint()) { + if (Op.LHS.first->getType()->isFloatingPointTy()) { ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r"); ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i"); } else { @@ -407,7 +407,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) { ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) { llvm::Value *ResR, *ResI; - if (Op.LHS.first->getType()->isFloatingPoint()) { + if (Op.LHS.first->getType()->isFloatingPointTy()) { ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r"); ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i"); } else { @@ -422,7 +422,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) { using llvm::Value; Value *ResR, *ResI; - if (Op.LHS.first->getType()->isFloatingPoint()) { + if (Op.LHS.first->getType()->isFloatingPointTy()) { Value *ResRl = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul.rl"); Value *ResRr = Builder.CreateFMul(Op.LHS.second, Op.RHS.second,"mul.rr"); ResR = Builder.CreateFSub(ResRl, ResRr, "mul.r"); @@ -448,7 +448,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { llvm::Value *DSTr, *DSTi; - if (Op.LHS.first->getType()->isFloatingPoint()) { + if (Op.LHS.first->getType()->isFloatingPointTy()) { // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr, "tmp"); // a*c llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi, "tmp"); // b*d diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 7d5b3da0b6c6..3df552d75bb6 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -418,12 +418,19 @@ public: // Get the function pointer (or index if this is a virtual function). if (MD->isVirtual()) { uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); - - // The pointer is 1 + the virtual table offset in bytes. + + // Itanium C++ ABI 2.3: + // For a non-virtual function, this field is a simple function pointer. + // For a virtual function, it is 1 plus the virtual table offset + // (in bytes) of the function, represented as a ptrdiff_t. Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); } else { - llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD); + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD, Ty); Values[0] = llvm::ConstantExpr::getPtrToInt(FuncPtr, PtrDiffTy); } @@ -438,16 +445,16 @@ public: if (const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>()) { QualType T = MPT->getPointeeType(); - if (T->isFunctionProtoType()) { - DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); - - return EmitMemberFunctionPointer(cast<CXXMethodDecl>(DRE->getDecl())); - } + DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); + + NamedDecl *ND = DRE->getDecl(); + if (T->isFunctionProtoType()) + return EmitMemberFunctionPointer(cast<CXXMethodDecl>(ND)); - // FIXME: Should we handle other member pointer types here too, - // or should they be handled by Expr::Evaluate? + // We have a pointer to data member. + return CGM.EmitPointerToDataMember(cast<FieldDecl>(ND)); } - + return 0; } @@ -534,8 +541,8 @@ public: llvm::ConstantStruct *CS = cast<llvm::ConstantStruct>(C); // Check if we need to update the adjustment. - if (llvm::Constant *Offset = CGM.GetCXXBaseClassOffset(DerivedClass, - BaseClass)) { + if (llvm::Constant *Offset = + CGM.GetNonVirtualBaseClassOffset(DerivedClass, BaseClass)) { llvm::Constant *Values[2]; Values[0] = CS->getOperand(0); @@ -668,6 +675,40 @@ public: return 0; } + llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) { + if (!E->getConstructor()->isTrivial()) + return 0; + + QualType Ty = E->getType(); + + // FIXME: We should not have to call getBaseElementType here. + const RecordType *RT = + CGM.getContext().getBaseElementType(Ty)->getAs<RecordType>(); + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + + // If the class doesn't have a trivial destructor, we can't emit it as a + // constant expr. + if (!RD->hasTrivialDestructor()) + return 0; + + // Only copy and default constructors can be trivial. + + + if (E->getNumArgs()) { + assert(E->getNumArgs() == 1 && "trivial ctor with > 1 argument"); + assert(E->getConstructor()->isCopyConstructor() && + "trivial ctor has argument but isn't a copy ctor"); + + Expr *Arg = E->getArg(0); + assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) && + "argument to copy ctor is of wrong type"); + + return Visit(Arg); + } + + return CGM.EmitNullConstant(Ty); + } + llvm::Constant *VisitStringLiteral(StringLiteral *E) { assert(!E->getType()->isPointerType() && "Strings are always arrays"); @@ -911,7 +952,24 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, return C; } -static inline bool isDataMemberPointerType(QualType T) { +static bool containsPointerToDataMember(CodeGenTypes &Types, QualType T) { + // No need to check for member pointers when not compiling C++. + if (!Types.getContext().getLangOptions().CPlusPlus) + return false; + + T = Types.getContext().getBaseElementType(T); + + 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); + return Layout.containsPointerToDataMember(); + } + if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) return !MPT->getPointeeType()->isFunctionType(); @@ -919,43 +977,80 @@ static inline bool isDataMemberPointerType(QualType T) { } llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { - // No need to check for member pointers when not compiling C++. - if (!getContext().getLangOptions().CPlusPlus) + if (!containsPointerToDataMember(getTypes(), T)) return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T)); - + if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) { QualType ElementTy = CAT->getElementType(); - // FIXME: Handle arrays of structs that contain member pointers. - if (isDataMemberPointerType(Context.getBaseElementType(ElementTy))) { - llvm::Constant *Element = EmitNullConstant(ElementTy); - uint64_t NumElements = CAT->getSize().getZExtValue(); - std::vector<llvm::Constant *> Array(NumElements); - for (uint64_t i = 0; i != NumElements; ++i) - Array[i] = Element; + llvm::Constant *Element = EmitNullConstant(ElementTy); + unsigned NumElements = CAT->getSize().getZExtValue(); + std::vector<llvm::Constant *> Array(NumElements); + for (unsigned i = 0; i != NumElements; ++i) + Array[i] = Element; - const llvm::ArrayType *ATy = - cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T)); - return llvm::ConstantArray::get(ATy, Array); - } + const llvm::ArrayType *ATy = + cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T)); + return llvm::ConstantArray::get(ATy, Array); } if (const RecordType *RT = T->getAs<RecordType>()) { - const RecordDecl *RD = 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.containsMemberPointer()) { - assert(0 && "FIXME: No support for structs with member pointers yet!"); + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + assert(!RD->getNumBases() && + "FIXME: Handle zero-initializing structs with bases and " + "pointers to data members."); + const llvm::StructType *STy = + cast<llvm::StructType>(getTypes().ConvertTypeForMem(T)); + unsigned NumElements = STy->getNumElements(); + std::vector<llvm::Constant *> Elements(NumElements); + + for (RecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I) { + const FieldDecl *FD = *I; + + unsigned FieldNo = getTypes().getLLVMFieldNo(FD); + Elements[FieldNo] = EmitNullConstant(FD->getType()); + } + + // Now go through all other fields and zero them out. + for (unsigned i = 0; i != NumElements; ++i) { + if (!Elements[i]) + Elements[i] = llvm::Constant::getNullValue(STy->getElementType(i)); } + + return llvm::ConstantStruct::get(STy, Elements); } - // FIXME: Handle structs that contain member pointers. - if (isDataMemberPointerType(T)) - return llvm::Constant::getAllOnesValue(getTypes().ConvertTypeForMem(T)); + assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() && + "Should only see pointers to data members here!"); + + // Itanium C++ ABI 2.3: + // A NULL pointer is represented as -1. + return llvm::ConstantInt::get(getTypes().ConvertTypeForMem(T), -1ULL, + /*isSigned=*/true); +} + +llvm::Constant * +CodeGenModule::EmitPointerToDataMember(const FieldDecl *FD) { + + // Itanium C++ ABI 2.3: + // A pointer to data member is an offset from the base address of the class + // object containing it, represented as a ptrdiff_t + + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(FD->getParent()); + QualType ClassType = + getContext().getTypeDeclType(const_cast<CXXRecordDecl *>(ClassDecl)); + + const llvm::StructType *ClassLTy = + cast<llvm::StructType>(getTypes().ConvertType(ClassType)); + + unsigned FieldNo = getTypes().getLLVMFieldNo(FD); + uint64_t Offset = + getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); + + const llvm::Type *PtrDiffTy = + getTypes().ConvertType(getContext().getPointerDiffType()); - return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T)); + return llvm::ConstantInt::get(PtrDiffTy, Offset); } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 690a7dc2fded..db0998b4dedc 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -290,7 +290,7 @@ public: if (CGF.getContext().getLangOptions().OverflowChecking && Ops.Ty->isSignedIntegerType()) return EmitOverflowCheckedBinOp(Ops); - if (Ops.LHS->getType()->isFPOrFPVector()) + if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); } @@ -388,8 +388,6 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { } if (SrcType->isMemberPointerType()) { - // FIXME: This is ABI specific. - // Compare against -1. llvm::Value *NegativeOne = llvm::Constant::getAllOnesValue(Src->getType()); return Builder.CreateICmpNE(Src, NegativeOne, "tobool"); @@ -507,7 +505,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, return Builder.CreateUIToFP(Src, DstTy, "conv"); } - assert(Src->getType()->isFloatingPoint() && "Unknown real conversion"); + assert(Src->getType()->isFloatingPointTy() && "Unknown real conversion"); if (isa<llvm::IntegerType>(DstTy)) { if (DstType->isSignedIntegerType()) return Builder.CreateFPToSI(Src, DstTy, "conv"); @@ -515,7 +513,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, return Builder.CreateFPToUI(Src, DstTy, "conv"); } - assert(DstTy->isFloatingPoint() && "Unknown real conversion"); + assert(DstTy->isFloatingPointTy() && "Unknown real conversion"); if (DstTy->getTypeID() < Src->getType()->getTypeID()) return Builder.CreateFPTrunc(Src, DstTy, "conv"); else @@ -891,8 +889,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) std::swap(DerivedDecl, BaseDecl); - llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl); - if (Adj) { + if (llvm::Constant *Adj = + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) { if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) Src = Builder.CreateSub(Src, Adj, "adj"); else @@ -1009,7 +1007,7 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) { Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { TestAndClearIgnoreResultAssign(); Value *Op = Visit(E->getSubExpr()); - if (Op->getType()->isFPOrFPVector()) + if (Op->getType()->isFPOrFPVectorTy()) return Builder.CreateFNeg(Op, "neg"); return Builder.CreateNeg(Op, "neg"); } @@ -1154,7 +1152,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { - if (Ops.LHS->getType()->isFPOrFPVector()) + if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); else if (Ops.Ty->isUnsignedIntegerType()) return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div"); @@ -1261,7 +1259,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { Ops.Ty->isSignedIntegerType()) return EmitOverflowCheckedBinOp(Ops); - if (Ops.LHS->getType()->isFPOrFPVector()) + if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFAdd(Ops.LHS, Ops.RHS, "add"); // Signed integer overflow is undefined behavior. @@ -1337,7 +1335,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { && Ops.Ty->isSignedIntegerType()) return EmitOverflowCheckedBinOp(Ops); - if (Ops.LHS->getType()->isFPOrFPVector()) + if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFSub(Ops.LHS, Ops.RHS, "sub"); return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub"); } @@ -1505,7 +1503,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); - if (LHS->getType()->isFPOrFPVector()) { + if (LHS->getType()->isFPOrFPVectorTy()) { Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc, LHS, RHS, "cmp"); } else if (LHSTy->isSignedIntegerType()) { @@ -1615,10 +1613,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI); - CGF.StartConditionalBranch(); + CGF.BeginConditionalBranch(); CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - CGF.FinishConditionalBranch(); + CGF.EndConditionalBranch(); // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); @@ -1665,13 +1663,13 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI); - CGF.StartConditionalBranch(); + CGF.BeginConditionalBranch(); // Emit the RHS condition as a bool value. CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - CGF.FinishConditionalBranch(); + CGF.EndConditionalBranch(); // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); @@ -1785,7 +1783,7 @@ VisitConditionalOperator(const ConditionalOperator *E) { Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock); } - CGF.StartConditionalBranch(); + CGF.BeginConditionalBranch(); CGF.EmitBlock(LHSBlock); // Handle the GNU extension for missing LHS. @@ -1795,15 +1793,15 @@ VisitConditionalOperator(const ConditionalOperator *E) { else // Perform promotions, to handle cases like "short ?: int" LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType()); - CGF.FinishConditionalBranch(); + CGF.EndConditionalBranch(); LHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); - CGF.StartConditionalBranch(); + CGF.BeginConditionalBranch(); CGF.EmitBlock(RHSBlock); Value *RHS = Visit(E->getRHS()); - CGF.FinishConditionalBranch(); + CGF.EndConditionalBranch(); RHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); @@ -1882,14 +1880,23 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { llvm::Value *V; // object->isa or (*object).isa // Generate code as for: *(Class*)object + // build Class* type + const llvm::Type *ClassPtrTy = ConvertType(E->getType()); + Expr *BaseExpr = E->getBase(); - if (E->isArrow()) - V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr); - else - V = EmitLValue(BaseExpr).getAddress(); + if (BaseExpr->isLvalue(getContext()) != Expr::LV_Valid) { + V = CreateTempAlloca(ClassPtrTy, "resval"); + llvm::Value *Src = EmitScalarExpr(BaseExpr); + Builder.CreateStore(Src, V); + } + else { + if (E->isArrow()) + V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr); + else + V = EmitLValue(BaseExpr).getAddress(); + } // build Class* type - const llvm::Type *ClassPtrTy = ConvertType(E->getType()); ClassPtrTy = ClassPtrTy->getPointerTo(); V = Builder.CreateBitCast(V, ClassPtrTy); LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 896d2207ea4b..b62e6ed44366 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -122,7 +122,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, E = OMD->param_end(); PI != E; ++PI) Args.push_back(std::make_pair(*PI, (*PI)->getType())); - StartFunction(OMD, OMD->getResultType(), Fn, Args, OMD->getLocEnd()); + StartFunction(OMD, OMD->getResultType(), Fn, Args, OMD->getLocStart()); } /// Generate an Objective-C method. An Objective-C method is a C function with @@ -190,7 +190,8 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy)); // FIXME: We shouldn't need to get the function info here, the // runtime already should have computed it to build the function. - RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args), + RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args, + CC_Default, false), 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 @@ -278,7 +279,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, getContext().BoolTy)); // FIXME: We shouldn't need to get the function info here, the runtime // already should have computed it to build the function. - EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args), SetPropertyFn, + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + CC_Default, false), SetPropertyFn, ReturnValueSlot(), Args); } else { // FIXME: Find a clean way to avoid AST node creation. @@ -450,9 +452,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ // Fast enumeration state. QualType StateTy = getContext().getObjCFastEnumerationStateType(); - llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy), - "state.ptr"); - StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3); + llvm::Value *StatePtr = CreateMemTemp(StateTy, "state.ptr"); EmitMemSetToZero(StatePtr, StateTy); // Number of elements in the items array. @@ -470,7 +470,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ getContext().getConstantArrayType(getContext().getObjCIdType(), llvm::APInt(32, NumItems), ArrayType::Normal, 0); - llvm::Value *ItemsPtr = CreateTempAlloca(ConvertType(ItemsTy), "items.ptr"); + llvm::Value *ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr"); llvm::Value *Collection = EmitScalarExpr(S.getCollection()); @@ -492,7 +492,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ FastEnumSel, Collection, false, Args); - llvm::Value *LimitPtr = CreateTempAlloca(UnsignedLongLTy, "limit.ptr"); + llvm::Value *LimitPtr = CreateMemTemp(getContext().UnsignedLongTy, + "limit.ptr"); Builder.CreateStore(CountRV.getScalarVal(), LimitPtr); llvm::BasicBlock *NoElements = createBasicBlock("noelements"); @@ -506,8 +507,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitBlock(SetStartMutations); - llvm::Value *StartMutationsPtr = - CreateTempAlloca(UnsignedLongLTy); + llvm::Value *StartMutationsPtr = CreateMemTemp(getContext().UnsignedLongTy); llvm::Value *StateMutationsPtrPtr = Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr"); @@ -522,7 +522,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ llvm::BasicBlock *LoopStart = createBasicBlock("loopstart"); EmitBlock(LoopStart); - llvm::Value *CounterPtr = CreateTempAlloca(UnsignedLongLTy, "counter.ptr"); + llvm::Value *CounterPtr = CreateMemTemp(getContext().UnsignedLongTy, + "counter.ptr"); Builder.CreateStore(Zero, CounterPtr); llvm::BasicBlock *LoopBody = createBasicBlock("loopbody"); @@ -553,7 +554,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ getContext().getObjCIdType())); // FIXME: We shouldn't need to get the function info here, the runtime already // should have computed it to build the function. - EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2), + EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2, + CC_Default, false), EnumerationMutationFn, ReturnValueSlot(), Args2); EmitBlock(WasNotMutated); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 77be9fb58231..1d38ef9e2d2f 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -55,6 +55,7 @@ private: const llvm::PointerType *PtrToInt8Ty; const llvm::FunctionType *IMPTy; const llvm::PointerType *IdTy; + const llvm::PointerType *PtrToIdTy; QualType ASTIdTy; const llvm::IntegerType *IntTy; const llvm::PointerType *PtrTy; @@ -65,11 +66,17 @@ private: std::vector<llvm::Constant*> Classes; std::vector<llvm::Constant*> Categories; std::vector<llvm::Constant*> ConstantStrings; + llvm::StringMap<llvm::Constant*> ObjCStrings; llvm::Function *LoadFunction; llvm::StringMap<llvm::Constant*> ExistingProtocols; typedef std::pair<std::string, std::string> TypedSelector; std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors; llvm::StringMap<llvm::GlobalAlias*> UntypedSelectors; + // Selectors that we don't emit in GC mode + Selector RetainSel, ReleaseSel, AutoreleaseSel; + // Functions used for GC. + llvm::Constant *IvarAssignFn, *StrongCastAssignFn, *MemMoveFn, *WeakReadFn, + *WeakAssignFn, *GlobalAssignFn; // Some zeros used for GEPs in lots of places. llvm::Constant *Zeros[2]; llvm::Constant *NULLPtr; @@ -114,14 +121,18 @@ private: llvm::Constant *ExportUniqueString(const std::string &Str, const std::string prefix); llvm::Constant *MakeGlobal(const llvm::StructType *Ty, - std::vector<llvm::Constant*> &V, const std::string &Name="", + std::vector<llvm::Constant*> &V, llvm::StringRef Name="", llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage); llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty, - std::vector<llvm::Constant*> &V, const std::string &Name="", + std::vector<llvm::Constant*> &V, llvm::StringRef Name="", llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage); llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar); void EmitClassRef(const std::string &className); + llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, const llvm::Type *Ty){ + if (V->getType() == Ty) return V; + return B.CreateBitCast(V, Ty); + } public: CGObjCGNU(CodeGen::CodeGenModule &cgm); virtual llvm::Constant *GenerateConstantString(const StringLiteral *); @@ -257,12 +268,54 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) } else { IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); } + PtrToIdTy = llvm::PointerType::getUnqual(IdTy); // IMP type std::vector<const llvm::Type*> IMPArgs; IMPArgs.push_back(IdTy); IMPArgs.push_back(SelectorTy); IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true); + + if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + // Get selectors needed in GC mode + RetainSel = GetNullarySelector("retain", CGM.getContext()); + ReleaseSel = GetNullarySelector("release", CGM.getContext()); + AutoreleaseSel = GetNullarySelector("autorelease", CGM.getContext()); + + // Get functions needed in GC mode + + // id objc_assign_ivar(id, id, ptrdiff_t); + std::vector<const llvm::Type*> Args(1, IdTy); + Args.push_back(PtrToIdTy); + // FIXME: ptrdiff_t + Args.push_back(LongTy); + llvm::FunctionType *FTy = llvm::FunctionType::get(IdTy, Args, false); + IvarAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar"); + // id objc_assign_strongCast (id, id*) + Args.pop_back(); + FTy = llvm::FunctionType::get(IdTy, Args, false); + StrongCastAssignFn = + CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast"); + // id objc_assign_global(id, id*); + FTy = llvm::FunctionType::get(IdTy, Args, false); + GlobalAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_global"); + // id objc_assign_weak(id, id*); + FTy = llvm::FunctionType::get(IdTy, Args, false); + WeakAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_weak"); + // id objc_read_weak(id*); + Args.clear(); + Args.push_back(PtrToIdTy); + FTy = llvm::FunctionType::get(IdTy, Args, false); + WeakReadFn = CGM.CreateRuntimeFunction(FTy, "objc_read_weak"); + // void *objc_memmove_collectable(void*, void *, size_t); + Args.clear(); + Args.push_back(PtrToInt8Ty); + Args.push_back(PtrToInt8Ty); + // FIXME: size_t + Args.push_back(LongTy); + FTy = llvm::FunctionType::get(IdTy, Args, false); + MemMoveFn = CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable"); + } } // This has to perform the lookup every time, since posing and related @@ -340,7 +393,7 @@ llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str, } llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty, - std::vector<llvm::Constant*> &V, const std::string &Name, + std::vector<llvm::Constant*> &V, llvm::StringRef Name, llvm::GlobalValue::LinkageTypes linkage) { llvm::Constant *C = llvm::ConstantStruct::get(Ty, V); return new llvm::GlobalVariable(TheModule, Ty, false, @@ -348,7 +401,7 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty, } llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, - std::vector<llvm::Constant*> &V, const std::string &Name, + std::vector<llvm::Constant*> &V, llvm::StringRef Name, llvm::GlobalValue::LinkageTypes linkage) { llvm::Constant *C = llvm::ConstantArray::get(Ty, V); return new llvm::GlobalVariable(TheModule, Ty, false, @@ -357,8 +410,14 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, /// Generate an NSConstantString object. llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { + std::string Str(SL->getStrData(), SL->getByteLength()); + // Look for an existing one + llvm::StringMap<llvm::Constant*>::iterator old = ObjCStrings.find(Str); + if (old != ObjCStrings.end()) + return old->getValue(); + std::vector<llvm::Constant*> Ivars; Ivars.push_back(NULLPtr); Ivars.push_back(MakeConstantString(Str)); @@ -366,8 +425,9 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { llvm::Constant *ObjCStr = MakeGlobal( llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL), Ivars, ".objc_str"); - ConstantStrings.push_back( - llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty)); + ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty); + ObjCStrings[Str] = ObjCStr; + ConstantStrings.push_back(ObjCStr); return ObjCStr; } @@ -384,6 +444,14 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { + if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + if (Sel == RetainSel || Sel == AutoreleaseSel) { + return RValue::get(Receiver); + } + if (Sel == ReleaseSel) { + return RValue::get(0); + } + } llvm::Value *cmd = GetSelector(CGF.Builder, Sel); CallArgList ActualArgs; @@ -396,7 +464,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); - const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); + const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, + CC_Default, false); const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); @@ -478,6 +547,14 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { + if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + if (Sel == RetainSel || Sel == AutoreleaseSel) { + return RValue::get(Receiver); + } + if (Sel == ReleaseSel) { + return RValue::get(0); + } + } CGBuilderTy &Builder = CGF.Builder; IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; @@ -495,7 +572,8 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); - const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); + const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, + CC_Default, false); const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); @@ -1517,7 +1595,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion)); } // sizeof(ModuleTy) - llvm::TargetData td = llvm::TargetData::TargetData(&TheModule); + llvm::TargetData td(&TheModule); Elements.push_back(llvm::ConstantInt::get(LongTy, td.getTypeSizeInBits(ModuleTy)/8)); //FIXME: Should be the path to the file where this module was declared @@ -1610,7 +1688,8 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { llvm::SmallVector<QualType,16> Params; Params.push_back(ASTIdTy); const llvm::FunctionType *FTy = - Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false); + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, + CC_Default, false), false); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } @@ -1668,7 +1747,6 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(TryHandler); // Get the correct versions of the exception handling intrinsics - llvm::TargetData td = llvm::TargetData::TargetData(&TheModule); llvm::Value *llvm_eh_exception = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); llvm::Value *llvm_eh_selector = @@ -1899,35 +1977,58 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, llvm::Value *AddrWeakObj) { - return 0; + CGBuilderTy B = CGF.Builder; + AddrWeakObj = EnforceType(B, AddrWeakObj, IdTy); + return B.CreateCall(WeakReadFn, AddrWeakObj); } void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - return; + CGBuilderTy B = CGF.Builder; + src = EnforceType(B, src, IdTy); + dst = EnforceType(B, dst, PtrToIdTy); + B.CreateCall2(WeakAssignFn, src, dst); } void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - return; + CGBuilderTy B = CGF.Builder; + src = EnforceType(B, src, IdTy); + dst = EnforceType(B, dst, PtrToIdTy); + B.CreateCall2(GlobalAssignFn, src, dst); } void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, llvm::Value *ivarOffset) { - return; + CGBuilderTy B = CGF.Builder; + src = EnforceType(B, src, IdTy); + dst = EnforceType(B, dst, PtrToIdTy); + B.CreateCall3(IvarAssignFn, src, dst, ivarOffset); } void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - return; + CGBuilderTy B = CGF.Builder; + src = EnforceType(B, src, IdTy); + dst = EnforceType(B, dst, PtrToIdTy); + B.CreateCall2(StrongCastAssignFn, src, dst); } void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, QualType Ty) { - return; + CGBuilderTy B = CGF.Builder; + DestPtr = EnforceType(B, DestPtr, IdTy); + SrcPtr = EnforceType(B, SrcPtr, PtrToIdTy); + + std::pair<uint64_t, unsigned> TypeInfo = CGM.getContext().getTypeInfo(Ty); + unsigned long size = TypeInfo.first/8; + // FIXME: size_t + llvm::Value *N = llvm::ConstantInt::get(LongTy, size); + + B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, N); } llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 137ea51721c7..b16a510f98f6 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -21,6 +21,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/LangOptions.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "llvm/Intrinsics.h" #include "llvm/LLVMContext.h" @@ -304,7 +305,8 @@ public: Params.push_back(Ctx.LongTy); Params.push_back(Ctx.BoolTy); const llvm::FunctionType *FTy = - Types.GetFunctionType(Types.getFunctionInfo(IdType, Params), false); + Types.GetFunctionType(Types.getFunctionInfo(IdType, Params, + CC_Default, false), false); return CGM.CreateRuntimeFunction(FTy, "objc_getProperty"); } @@ -322,7 +324,8 @@ public: Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); const llvm::FunctionType *FTy = - Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false); + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, + CC_Default, false), false); return CGM.CreateRuntimeFunction(FTy, "objc_setProperty"); } @@ -333,7 +336,8 @@ public: llvm::SmallVector<QualType,16> Params; Params.push_back(Ctx.getObjCIdType()); const llvm::FunctionType *FTy = - Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false); + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, + CC_Default, false), false); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } @@ -734,7 +738,8 @@ public: return CGM.CreateRuntimeFunction( llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false), - "_Unwind_Resume_or_Rethrow"); + (CGM.getLangOptions().SjLjExceptions ? "_Unwind_SjLj_Resume" : + "_Unwind_Resume_or_Rethrow")); } llvm::Constant *getObjCEndCatchFn() { @@ -1553,7 +1558,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); - const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); + const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, + CC_Default, false); const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); @@ -3625,7 +3631,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) Ctx.getObjCIdType(), 0, 0, false)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, Ctx.getObjCClassType(), 0, 0, false)); - RD->completeDefinition(Ctx); + RD->completeDefinition(); SuperCTy = Ctx.getTagDeclType(RD); SuperPtrCTy = Ctx.getPointerType(SuperCTy); @@ -4086,7 +4092,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul Ctx.VoidPtrTy, 0, 0, false)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, Ctx.getObjCSelType(), 0, 0, false)); - RD->completeDefinition(Ctx); + RD->completeDefinition(); MessageRefCTy = Ctx.getTagDeclType(RD); MessageRefCPtrTy = Ctx.getPointerType(MessageRefCTy); @@ -4224,6 +4230,9 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { /// message dispatch call for all the rest. /// bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { + if (CGM.getCodeGenOpts().ObjCLegacyDispatch) + return true; + if (NonLegacyDispatchMethods.empty()) { NonLegacyDispatchMethods.insert(GetNullarySelector("alloc")); NonLegacyDispatchMethods.insert(GetNullarySelector("class")); @@ -5085,7 +5094,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, - llvm::SmallVector<QualType, 16>()); + llvm::SmallVector<QualType, 16>(), + CC_Default, false); llvm::Constant *Fn = 0; std::string Name("\01l_"); if (CGM.ReturnTypeUsesSret(FnInfo)) { @@ -5159,7 +5169,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( ActualArgs.push_back(std::make_pair(RValue::get(Arg1), ObjCTypes.MessageRefCPtrTy)); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); - const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs); + const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs, + CC_Default, false); 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/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 29552ce4441c..5236d2063489 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -256,6 +256,9 @@ bool ShouldUseExternalRTTIDescriptor(QualType Ty) { if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (!RD->hasDefinition()) + return false; + if (!RD->isDynamicClass()) return false; @@ -469,7 +472,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); - if (!RD->getNumBases()) { + if (!RD->hasDefinition() || !RD->getNumBases()) { // abi::__class_type_info. VtableName = "_ZTVN10__cxxabiv117__class_type_infoE"; } else if (CanUseSingleInheritance(RD)) { @@ -566,7 +569,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) { case Type::Record: { const CXXRecordDecl *RD = cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); - if (!RD->getNumBases()) { + if (!RD->hasDefinition() || !RD->getNumBases()) { // We don't need to emit any fields. break; } diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 9f90ec5ff6e0..baafd6836c63 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -108,6 +108,9 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, return true; } + // 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; @@ -162,6 +165,8 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { uint64_t Size = 0; 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) { @@ -181,6 +186,8 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { } else Types.addFieldInfo(*Field, 0); + HasOnlyZeroSizedBitFields = false; + const llvm::Type *FieldTy = Types.ConvertTypeForMemRecursive(Field->getType()); unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy); @@ -207,7 +214,8 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { } } if (!Align) { - assert((D->field_begin() == D->field_end()) && "LayoutUnion - Align 0"); + assert(HasOnlyZeroSizedBitFields && + "0-align record did not have all zero-sized bit-fields!"); Align = 1; } @@ -333,23 +341,34 @@ uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const { return Types.getTargetData().getTypeAllocSize(Ty); } -void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) { +void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) { // This record already contains a member pointer. - if (ContainsMemberPointer) + if (ContainsPointerToDataMember) return; // Can only have member pointers if we're compiling C++. if (!Types.getContext().getLangOptions().CPlusPlus) return; - QualType Ty = FD->getType(); - - if (Ty->isMemberPointerType()) { - // We have a member pointer! - ContainsMemberPointer = true; - return; - } + T = Types.getContext().getBaseElementType(T); + if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) { + if (!MPT->getPointeeType()->isFunctionType()) { + // We have a pointer to data member. + ContainsPointerToDataMember = true; + } + } 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 * @@ -381,5 +400,5 @@ CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types, Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size); } - return new CGRecordLayout(Ty, Builder.ContainsMemberPointer); + return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); } diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h index cf84053e1907..eb60ed7b5b1d 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.h +++ b/lib/CodeGen/CGRecordLayoutBuilder.h @@ -27,6 +27,7 @@ namespace clang { class CXXRecordDecl; class FieldDecl; class RecordDecl; + class QualType; namespace CodeGen { class CGRecordLayout; @@ -38,9 +39,10 @@ class CGRecordLayoutBuilder { /// Packed - Whether the resulting LLVM struct will be packed or not. bool Packed; - /// ContainsMemberPointer - Whether one of the fields is a member pointer - /// or is a struct that contains a member pointer. - bool ContainsMemberPointer; + /// 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; @@ -78,7 +80,7 @@ class CGRecordLayoutBuilder { llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields; CGRecordLayoutBuilder(CodeGenTypes &Types) - : Types(Types), Packed(false), ContainsMemberPointer(false) + : Types(Types), Packed(false), ContainsPointerToDataMember(false) , Alignment(0), AlignmentAsLLVMStruct(1) , BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { } @@ -123,8 +125,9 @@ class CGRecordLayoutBuilder { unsigned getTypeAlignment(const llvm::Type *Ty) const; uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const; - /// CheckForMemberPointer - Check if the field contains a member pointer. - void CheckForMemberPointer(const FieldDecl *FD); + /// 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. diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index bbd546261800..008a480b9c12 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -861,14 +861,13 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, std::string &ConstraintStr) { llvm::Value *Arg; if (Info.allowsRegister() || !Info.allowsMemory()) { - const llvm::Type *Ty = ConvertType(InputExpr->getType()); - - if (Ty->isSingleValueType()) { + if (!CodeGenFunction::hasAggregateLLVMType(InputExpr->getType())) { Arg = EmitScalarExpr(InputExpr); } else { InputExpr = InputExpr->IgnoreParenNoopCasts(getContext()); LValue Dest = EmitLValue(InputExpr); + const llvm::Type *Ty = ConvertType(InputExpr->getType()); uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty); if (Size <= 64 && llvm::isPowerOf2_64(Size)) { Ty = llvm::IntegerType::get(VMContext, Size); @@ -916,18 +915,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), S.getOutputName(i)); - bool result = Target.validateOutputConstraint(Info); - assert(result && "Failed to parse output constraint"); result=result; + assert(Target.validateOutputConstraint(Info) && + "Failed to parse output constraint"); OutputConstraintInfos.push_back(Info); } for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) { TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), S.getInputName(i)); - bool result = Target.validateInputConstraint(OutputConstraintInfos.data(), - S.getNumOutputs(), - Info); result=result; - assert(result && "Failed to parse input constraint"); + assert(Target.validateInputConstraint(OutputConstraintInfos.data(), + S.getNumOutputs(), + Info) && + "Failed to parse input constraint"); InputConstraintInfos.push_back(Info); } @@ -1066,10 +1065,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Clobbers for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { - std::string Clobber(S.getClobber(i)->getStrData(), - S.getClobber(i)->getByteLength()); + llvm::StringRef Clobber = S.getClobber(i)->getString(); - Clobber = Target.getNormalizedGCCRegisterName(Clobber.c_str()); + Clobber = Target.getNormalizedGCCRegisterName(Clobber); if (i != 0 || NumConstraints != 0) Constraints += ','; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index e5abfc6f8d57..970bbd777f14 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -16,14 +16,1245 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" #include <cstdio> using namespace clang; using namespace CodeGen; namespace { + +/// FinalOverriders - Contains the final overrider member functions for all +/// member functions in the base subobjects of a class. +class FinalOverriders { +public: + /// BaseOffset - Represents an offset from a derived class to a direct or + /// indirect base class. + struct BaseOffset { + /// DerivedClass - The derived class. + const CXXRecordDecl *DerivedClass; + + /// VirtualBase - If the path from the derived class to the base class + /// involves a virtual base class, this holds its declaration. + const CXXRecordDecl *VirtualBase; + + /// NonVirtualOffset - The offset from the derived class to the base class. + /// Or the offset from the virtual base class to the base class, if the path + /// from the derived class to the base class involves a virtual base class. + int64_t NonVirtualOffset; + + BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } + BaseOffset(const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) + : DerivedClass(DerivedClass), VirtualBase(VirtualBase), + NonVirtualOffset(NonVirtualOffset) { } + + bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } + }; + + /// OverriderInfo - Information about a final overrider. + struct OverriderInfo { + /// Method - The method decl of the overrider. + const CXXMethodDecl *Method; + + OverriderInfo() : Method(0) { } + }; + +private: + /// MostDerivedClass - The most derived class for which the final overriders + /// are stored. + const CXXRecordDecl *MostDerivedClass; + + ASTContext &Context; + + /// MostDerivedClassLayout - the AST record layout of the most derived class. + const ASTRecordLayout &MostDerivedClassLayout; + + /// BaseSubobjectMethodPairTy - Uniquely identifies a member function + /// in a base subobject. + typedef std::pair<BaseSubobject, const CXXMethodDecl *> + BaseSubobjectMethodPairTy; + + typedef llvm::DenseMap<BaseSubobjectMethodPairTy, + OverriderInfo> OverridersMapTy; + + /// OverridersMap - The final overriders for all virtual member functions of + /// all the base subobjects of the most derived class. + OverridersMapTy OverridersMap; + + /// VisitedVirtualBases - A set of all the visited virtual bases, used to + /// avoid visiting virtual bases more than once. + llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; + + typedef llvm::DenseMap<BaseSubobjectMethodPairTy, BaseOffset> + AdjustmentOffsetsMapTy; + + /// ReturnAdjustments - Holds return adjustments for all the overriders that + /// need to perform return value adjustments. + AdjustmentOffsetsMapTy ReturnAdjustments; + + /// ThisAdjustments - Holds 'this' adjustments for all the overriders that + /// need them. + AdjustmentOffsetsMapTy ThisAdjustments; + + typedef llvm::SmallVector<uint64_t, 1> OffsetVectorTy; + + /// SubobjectOffsetsMapTy - This map is used for keeping track of all the + /// base subobject offsets that a single class declaration might refer to. + /// + /// For example, in: + /// + /// struct A { virtual void f(); }; + /// struct B1 : A { }; + /// struct B2 : A { }; + /// struct C : B1, B2 { virtual void f(); }; + /// + /// when we determine that C::f() overrides A::f(), we need to update the + /// overriders map for both A-in-B1 and A-in-B2 and the subobject offsets map + /// will have the subobject offsets for both A copies. + typedef llvm::DenseMap<const CXXRecordDecl *, OffsetVectorTy> + SubobjectOffsetsMapTy; + + /// ComputeFinalOverriders - Compute the final overriders for a given base + /// subobject (and all its direct and indirect bases). + void ComputeFinalOverriders(BaseSubobject Base, + SubobjectOffsetsMapTy &Offsets); + + /// AddOverriders - Add the final overriders for this base subobject to the + /// map of final overriders. + void AddOverriders(BaseSubobject Base, SubobjectOffsetsMapTy &Offsets); + + /// PropagateOverrider - Propagate the NewMD overrider to all the functions + /// that OldMD overrides. For example, if we have: + /// + /// struct A { virtual void f(); }; + /// struct B : A { virtual void f(); }; + /// struct C : B { virtual void f(); }; + /// + /// and we want to override B::f with C::f, we also need to override A::f with + /// C::f. + void PropagateOverrider(const CXXMethodDecl *OldMD, + BaseSubobject NewBase, + const CXXMethodDecl *NewMD, + SubobjectOffsetsMapTy &Offsets); + + /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting + /// the 'this' pointer from the base subobject to the derived subobject. + BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived); + + static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, + SubobjectOffsetsMapTy &Offsets); + +public: + explicit FinalOverriders(const CXXRecordDecl *MostDerivedClass); + + /// getOverrider - Get the final overrider for the given method declaration in + /// the given base subobject. + OverriderInfo getOverrider(BaseSubobject Base, + const CXXMethodDecl *MD) const { + assert(OverridersMap.count(std::make_pair(Base, MD)) && + "Did not find overrider!"); + + return OverridersMap.lookup(std::make_pair(Base, MD)); + } + + /// getReturnAdjustmentOffset - Get the return adjustment offset for the + /// method decl in the given base subobject. Returns an empty base offset if + /// no adjustment is needed. + BaseOffset getReturnAdjustmentOffset(BaseSubobject Base, + const CXXMethodDecl *MD) const { + return ReturnAdjustments.lookup(std::make_pair(Base, MD)); + } + + /// getThisAdjustmentOffset - Get the 'this' pointer adjustment offset for the + /// method decl in the given base subobject. Returns an empty base offset if + /// no adjustment is needed. + BaseOffset getThisAdjustmentOffset(BaseSubobject Base, + const CXXMethodDecl *MD) const { + return ThisAdjustments.lookup(std::make_pair(Base, MD)); + } + + /// dump - dump the final overriders. + void dump() { + assert(VisitedVirtualBases.empty() && + "Visited virtual bases aren't empty!"); + dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0)); + VisitedVirtualBases.clear(); + } + + /// dump - dump the final overriders for a base subobject, and all its direct + /// and indirect base subobjects. + void dump(llvm::raw_ostream &Out, BaseSubobject Base); +}; + +FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass) + : MostDerivedClass(MostDerivedClass), + Context(MostDerivedClass->getASTContext()), + MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) { + + // Compute the final overriders. + SubobjectOffsetsMapTy Offsets; + ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), Offsets); + + // And dump them (for now). + dump(); + + // Also dump the base offsets (for now). + for (SubobjectOffsetsMapTy::const_iterator I = Offsets.begin(), + E = Offsets.end(); I != E; ++I) { + const OffsetVectorTy& OffsetVector = I->second; + + llvm::errs() << "Base offsets for "; + llvm::errs() << I->first->getQualifiedNameAsString() << '\n'; + + for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) + llvm::errs() << " " << I << " - " << OffsetVector[I] << '\n'; + } +} + +void FinalOverriders::AddOverriders(BaseSubobject Base, + SubobjectOffsetsMapTy &Offsets) { + const CXXRecordDecl *RD = Base.getBase(); + + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + // First, propagate the overrider. + PropagateOverrider(MD, Base, MD, Offsets); + + // Add the overrider as the final overrider of itself. + OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)]; + assert(!Overrider.Method && "Overrider should not exist yet!"); + + Overrider.Method = MD; + } +} + +static FinalOverriders::BaseOffset +ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *DerivedRD, + const CXXBasePath &Path) { + int64_t NonVirtualOffset = 0; + + unsigned NonVirtualStart = 0; + const CXXRecordDecl *VirtualBase = 0; + + // First, look for the virtual base class. + for (unsigned I = 0, E = Path.size(); I != E; ++I) { + const CXXBasePathElement &Element = Path[I]; + + if (Element.Base->isVirtual()) { + // FIXME: Can we break when we find the first virtual base? + // (If we can't, can't we just iterate over the path in reverse order?) + NonVirtualStart = I + 1; + QualType VBaseType = Element.Base->getType(); + VirtualBase = + cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl()); + } + } + + // Now compute the non-virtual offset. + for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) { + const CXXBasePathElement &Element = Path[I]; + + // Check the base class offset. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); + + const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); + const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); + + NonVirtualOffset += Layout.getBaseClassOffset(Base); + } + + // FIXME: This should probably use CharUnits or something. Maybe we should + // even change the base offsets in ASTRecordLayout to be specified in + // CharUnits. + return FinalOverriders::BaseOffset(DerivedRD, VirtualBase, + NonVirtualOffset / 8); + +} + +static FinalOverriders::BaseOffset +ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *BaseRD, + const CXXRecordDecl *DerivedRD) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + + if (!const_cast<CXXRecordDecl *>(DerivedRD)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return FinalOverriders::BaseOffset(); + } + + return ComputeBaseOffset(Context, DerivedRD, Paths.front()); +} + +static FinalOverriders::BaseOffset +ComputeReturnAdjustmentBaseOffset(ASTContext &Context, + const CXXMethodDecl *DerivedMD, + const CXXMethodDecl *BaseMD) { + const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>(); + const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>(); + + // Canonicalize the return types. + CanQualType CanDerivedReturnType = + Context.getCanonicalType(DerivedFT->getResultType()); + CanQualType CanBaseReturnType = + Context.getCanonicalType(BaseFT->getResultType()); + + assert(CanDerivedReturnType->getTypeClass() == + CanBaseReturnType->getTypeClass() && + "Types must have same type class!"); + + if (CanDerivedReturnType == CanBaseReturnType) { + // No adjustment needed. + return FinalOverriders::BaseOffset(); + } + + if (isa<ReferenceType>(CanDerivedReturnType)) { + CanDerivedReturnType = + CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType(); + CanBaseReturnType = + CanBaseReturnType->getAs<ReferenceType>()->getPointeeType(); + } else if (isa<PointerType>(CanDerivedReturnType)) { + CanDerivedReturnType = + CanDerivedReturnType->getAs<PointerType>()->getPointeeType(); + CanBaseReturnType = + CanBaseReturnType->getAs<PointerType>()->getPointeeType(); + } else { + assert(false && "Unexpected return type!"); + } + + // We need to compare unqualified types here; consider + // const T *Base::foo(); + // T *Derived::foo(); + if (CanDerivedReturnType.getUnqualifiedType() == + CanBaseReturnType.getUnqualifiedType()) { + // No adjustment needed. + return FinalOverriders::BaseOffset(); + } + + const CXXRecordDecl *DerivedRD = + cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl()); + + const CXXRecordDecl *BaseRD = + cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl()); + + return ComputeBaseOffset(Context, BaseRD, DerivedRD); +} + +FinalOverriders::BaseOffset +FinalOverriders::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) { + const CXXRecordDecl *BaseRD = Base.getBase(); + const CXXRecordDecl *DerivedRD = Derived.getBase(); + + CXXBasePaths Paths(/*FindAmbiguities=*/true, + /*RecordPaths=*/true, /*DetectVirtual=*/true); + + if (!const_cast<CXXRecordDecl *>(DerivedRD)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return FinalOverriders::BaseOffset(); + } + + assert(!Paths.getDetectedVirtual() && "FIXME: Handle virtual bases!"); + + BaseOffset Offset; + + // FIXME: This is not going to be enough with virtual bases. + // FIXME: We should not use / 8 here. + int64_t DerivedToBaseOffset = + (Base.getBaseOffset() - Derived.getBaseOffset()) / 8; + + Offset.NonVirtualOffset = -DerivedToBaseOffset; + + return Offset; +} + +void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD, + BaseSubobject NewBase, + const CXXMethodDecl *NewMD, + SubobjectOffsetsMapTy &Offsets) { + for (CXXMethodDecl::method_iterator I = OldMD->begin_overridden_methods(), + E = OldMD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); + + // We want to override OverriddenMD in all subobjects, for example: + // + /// struct A { virtual void f(); }; + /// struct B1 : A { }; + /// struct B2 : A { }; + /// struct C : B1, B2 { virtual void f(); }; + /// + /// When overriding A::f with C::f we need to do so in both A subobjects. + const OffsetVectorTy &OffsetVector = Offsets[OverriddenRD]; + + // Go through all the subobjects. + for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) { + uint64_t Offset = OffsetVector[I]; + + BaseSubobject OverriddenSubobject = BaseSubobject(OverriddenRD, Offset); + BaseSubobjectMethodPairTy SubobjectAndMethod = + std::make_pair(OverriddenSubobject, OverriddenMD); + + OverriderInfo &Overrider = OverridersMap[SubobjectAndMethod]; + + assert(Overrider.Method && "Did not find existing overrider!"); + + // Check if we need return adjustments or base adjustments. + // (We don't want to do this for pure virtual member functions). + if (!NewMD->isPure()) { + // Get the return adjustment base offset. + BaseOffset ReturnBaseOffset = + ComputeReturnAdjustmentBaseOffset(Context, NewMD, OverriddenMD); + + if (!ReturnBaseOffset.isEmpty()) { + // Store the return adjustment base offset. + ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset; + } + + // Check if we need a 'this' adjustment base offset as well. + if (Offset != NewBase.getBaseOffset()) { + BaseOffset ThisBaseOffset = + ComputeThisAdjustmentBaseOffset(OverriddenSubobject, + NewBase); + assert(!ThisBaseOffset.isEmpty() && + "Should not get an empty 'this' adjustment!"); + + ThisAdjustments[SubobjectAndMethod] = ThisBaseOffset; + } + } + + // Set the new overrider. + Overrider.Method = NewMD; + + // And propagate it further. + PropagateOverrider(OverriddenMD, NewBase, NewMD, Offsets); + } + } +} + +void +FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, + SubobjectOffsetsMapTy &Offsets) { + // Iterate over the new offsets. + for (SubobjectOffsetsMapTy::const_iterator I = NewOffsets.begin(), + E = NewOffsets.end(); I != E; ++I) { + const CXXRecordDecl *NewRD = I->first; + const OffsetVectorTy& NewOffsetVector = I->second; + + OffsetVectorTy &OffsetVector = Offsets[NewRD]; + if (OffsetVector.empty()) { + // There were no previous offsets in this vector, just insert all entries + // from the new offset vector. + OffsetVector.append(NewOffsetVector.begin(), NewOffsetVector.end()); + continue; + } + + // We need to merge the new offsets vector into the old, but we don't want + // to have duplicate entries. Do this by inserting the old offsets in a set + // so they'll be unique. After this, we iterate over the new offset vector + // and only append elements that aren't in the set. + + // First, add the existing offsets to the set. + llvm::SmallSet<uint64_t, 4> OffsetSet; + for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) { + bool Inserted = OffsetSet.insert(OffsetVector[I]); + if (!Inserted) + assert(false && "Set of offsets should be unique!"); + } + + // Next, only add the new offsets if they are not already in the set. + for (unsigned I = 0, E = NewOffsetVector.size(); I != E; ++I) { + uint64_t Offset = NewOffsetVector[I]; + + if (OffsetSet.count(Offset)) { + // Ignore the offset. + continue; + } + + // Otherwise, add it to the offsets vector. + OffsetVector.push_back(Offset); + } + } +} + +void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base, + SubobjectOffsetsMapTy &Offsets) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + SubobjectOffsetsMapTy NewOffsets; + + 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()); + + // Ignore bases that don't have any virtual member functions. + if (!BaseDecl->isPolymorphic()) + continue; + + uint64_t BaseOffset; + if (I->isVirtual()) { + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); + } + + // Compute the final overriders for this base. + ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), NewOffsets); + } + + /// Now add the overriders for this particular subobject. + AddOverriders(Base, NewOffsets); + + // And merge the newly discovered subobject offsets. + MergeSubobjectOffsets(NewOffsets, Offsets); + + /// Finally, add the offset for our own subobject. + Offsets[RD].push_back(Base.getBaseOffset()); +} + +void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + 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()); + + // Ignore bases that don't have any virtual member functions. + if (!BaseDecl->isPolymorphic()) + continue; + + uint64_t BaseOffset; + if (I->isVirtual()) { + if (!VisitedVirtualBases.insert(BaseDecl)) { + // We've visited this base before. + continue; + } + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffset = Layout.getBaseClassOffset(BaseDecl) + + Base.getBaseOffset(); + } + + dump(Out, BaseSubobject(BaseDecl, BaseOffset)); + } + + Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", "; + Out << Base.getBaseOffset() << ")\n"; + + // Now dump the overriders for this base subobject. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + OverriderInfo Overrider = getOverrider(Base, MD); + + Out << " " << MD->getQualifiedNameAsString() << " - "; + Out << Overrider.Method->getQualifiedNameAsString(); + + AdjustmentOffsetsMapTy::const_iterator AI = + ReturnAdjustments.find(std::make_pair(Base, MD)); + if (AI != ReturnAdjustments.end()) { + const BaseOffset &Offset = AI->second; + + Out << " [ret-adj: "; + if (Offset.VirtualBase) + Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; + + Out << Offset.NonVirtualOffset << " nv]"; + } + + AI = ThisAdjustments.find(std::make_pair(Base, MD)); + if (AI != ThisAdjustments.end()) { + const BaseOffset &Offset = AI->second; + + Out << " [this-adj: "; + if (Offset.VirtualBase) + Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; + + Out << Offset.NonVirtualOffset << " nv]"; + } + + Out << "\n"; + } +} + +/// VtableComponent - Represents a single component in a vtable. +class VtableComponent { +public: + enum Kind { + CK_VCallOffset, + CK_VBaseOffset, + CK_OffsetToTop, + CK_RTTI, + CK_FunctionPointer, + + /// CK_CompleteDtorPointer - A pointer to the complete destructor. + CK_CompleteDtorPointer, + + /// CK_DeletingDtorPointer - A pointer to the deleting destructor. + CK_DeletingDtorPointer + }; + + static VtableComponent MakeVBaseOffset(int64_t Offset) { + return VtableComponent(CK_VBaseOffset, Offset); + } + + static VtableComponent MakeOffsetToTop(int64_t Offset) { + return VtableComponent(CK_OffsetToTop, Offset); + } + + static VtableComponent MakeRTTI(const CXXRecordDecl *RD) { + return VtableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); + } + + static VtableComponent MakeFunction(const CXXMethodDecl *MD) { + assert(!isa<CXXDestructorDecl>(MD) && + "Don't use MakeFunction with destructors!"); + + return VtableComponent(CK_FunctionPointer, + reinterpret_cast<uintptr_t>(MD)); + } + + static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { + return VtableComponent(CK_CompleteDtorPointer, + reinterpret_cast<uintptr_t>(DD)); + } + + static VtableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { + return VtableComponent(CK_DeletingDtorPointer, + reinterpret_cast<uintptr_t>(DD)); + } + + /// getKind - Get the kind of this vtable component. + Kind getKind() const { + return (Kind)(Value & 0x7); + } + + int64_t getVBaseOffset() const { + assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); + + return getOffset(); + } + + int64_t getOffsetToTop() const { + assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); + + return getOffset(); + } + + const CXXRecordDecl *getRTTIDecl() const { + assert(getKind() == CK_RTTI && "Invalid component kind!"); + + return reinterpret_cast<CXXRecordDecl *>(getPointer()); + } + + const CXXMethodDecl *getFunctionDecl() const { + assert(getKind() == CK_FunctionPointer); + + return reinterpret_cast<CXXMethodDecl *>(getPointer()); + } + + const CXXDestructorDecl *getDestructorDecl() const { + assert((getKind() == CK_CompleteDtorPointer || + getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); + + return reinterpret_cast<CXXDestructorDecl *>(getPointer()); + } + +private: + VtableComponent(Kind ComponentKind, int64_t Offset) { + assert((ComponentKind == CK_VCallOffset || + ComponentKind == CK_VBaseOffset || + ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); + assert(Offset <= ((1LL << 56) - 1) && "Offset is too big!"); + + Value = ((Offset << 3) | ComponentKind); + } + + VtableComponent(Kind ComponentKind, uintptr_t Ptr) { + assert((ComponentKind == CK_RTTI || + ComponentKind == CK_FunctionPointer || + ComponentKind == CK_CompleteDtorPointer || + ComponentKind == CK_DeletingDtorPointer) && + "Invalid component kind!"); + + assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); + + Value = Ptr | ComponentKind; + } + + int64_t getOffset() const { + assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || + getKind() == CK_OffsetToTop) && "Invalid component kind!"); + + return Value >> 3; + } + + uintptr_t getPointer() const { + assert((getKind() == CK_RTTI || + getKind() == CK_FunctionPointer || + getKind() == CK_CompleteDtorPointer || + getKind() == CK_DeletingDtorPointer) && + "Invalid component kind!"); + + return static_cast<uintptr_t>(Value & ~7ULL); + } + + /// 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. + /// (The reason that we're not simply using a PointerIntPair here is that we + /// need the offsets to be 64-bit, even when on a 32-bit machine). + int64_t Value; +}; + +/// VtableBuilder - Class for building vtable layout information. class VtableBuilder { public: + /// PrimaryBasesSetTy - A set of direct and indirect primary bases. + typedef llvm::SmallPtrSet<const CXXRecordDecl *, 8> PrimaryBasesSetTy; + +private: + /// VtableInfo - Global vtable information. + CGVtableInfo &VtableInfo; + + /// MostDerivedClass - The most derived class for which we're building this + /// vtable. + const CXXRecordDecl *MostDerivedClass; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// FinalOverriders - The final overriders of the most derived class. + FinalOverriders Overriders; + + /// VCallAndVBaseOffsets - The vcall and vbase offset, of the vtable we're + // building (in reverse order). + llvm::SmallVector<VtableComponent, 64> VCallAndVBaseOffsets; + + /// Components - The components of the vtable being built. + 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; } + }; + + /// ReturnAdjustments - The return adjustments needed in this vtable. + llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16> + ReturnAdjustments; + + /// 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; + + /// FIXME: Add VCallOffsetOffset here. + + ThisAdjustment() : NonVirtual(0) { } + + bool isEmpty() const { return !NonVirtual; } + }; + + /// ThisAdjustments - The 'this' pointer adjustments needed in this vtable. + llvm::SmallVector<std::pair<uint64_t, ThisAdjustment>, 16> + ThisAdjustments; + + typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; + + /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the + /// given class. + void AddVCallAndVBaseOffsets(const CXXRecordDecl *RD, int64_t OffsetToTop, + VisitedVirtualBasesSetTy &VBases); + + /// AddVBaseOffsets - Add vbase offsets for the given class. + void AddVBaseOffsets(const CXXRecordDecl *RD, int64_t OffsetToTop, + VisitedVirtualBasesSetTy &VBases); + + /// ComputeReturnAdjustment - Compute the return adjustment given a return + /// adjustment base offset. + ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset); + + /// ComputeThisAdjustment - Compute the 'this' pointer adjustment given a + /// 'this' pointer adjustment base offset. + ThisAdjustment ComputeThisAdjustment(FinalOverriders::BaseOffset Offset); + + /// AddMethod - Add a single virtual member function to the vtable + /// components vector. + void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment, + ThisAdjustment ThisAdjustment); + + /// AddMethods - Add the methods of this base subobject and all its + /// primary bases to the vtable components vector. + void AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases); + + /// LayoutVtable - Layout a vtable and all its secondary vtables. + void LayoutVtable(BaseSubobject Base); + +public: + VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass) + : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass), + Context(MostDerivedClass->getASTContext()), Overriders(MostDerivedClass) { + + LayoutVtable(BaseSubobject(MostDerivedClass, 0)); + } + + /// dumpLayout - Dump the vtable layout. + void dumpLayout(llvm::raw_ostream&); +}; + +/// OverridesMethodInPrimaryBase - Checks whether whether this virtual member +/// function overrides a member function in a direct or indirect primary base. +/// Returns the overridden member function, or null if none was found. +static const CXXMethodDecl * +OverridesMethodInPrimaryBase(const CXXMethodDecl *MD, + VtableBuilder::PrimaryBasesSetTy &PrimaryBases) { + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); + assert(OverriddenMD->isCanonicalDecl() && + "Should have the canonical decl of the overridden RD!"); + + if (PrimaryBases.count(OverriddenRD)) + return OverriddenMD; + } + + return 0; +} + +VtableBuilder::ReturnAdjustment +VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) { + ReturnAdjustment Adjustment; + + if (!Offset.isEmpty()) { + if (Offset.VirtualBase) { + // Get the virtual base offset offset. + Adjustment.VBaseOffsetOffset = + VtableInfo.getVirtualBaseOffsetIndex(Offset.DerivedClass, + Offset.VirtualBase); + // FIXME: Once the assert in getVirtualBaseOffsetIndex is back again, + // we can get rid of this assert. + assert(Adjustment.VBaseOffsetOffset != 0 && + "Invalid base offset offset!"); + } + + Adjustment.NonVirtual = Offset.NonVirtualOffset; + } + + return Adjustment; +} + +VtableBuilder::ThisAdjustment +VtableBuilder::ComputeThisAdjustment(FinalOverriders::BaseOffset Offset) { + ThisAdjustment Adjustment; + + if (!Offset.isEmpty()) { + assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!"); + Adjustment.NonVirtual = Offset.NonVirtualOffset; + } + + return Adjustment; +} + +void +VtableBuilder::AddVCallAndVBaseOffsets(const CXXRecordDecl *RD, + int64_t OffsetToTop, + VisitedVirtualBasesSetTy &VBases) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Itanium C++ ABI 2.5.2: + // ..in classes sharing a virtual table with a primary base class, the vcall + // and vbase offsets added by the derived class all come before the vcall + // and vbase offsets required by the base class, so that the latter may be + // laid out as required by the base class without regard to additions from + // the derived class(es). + + // (Since we're emitting the vcall and vbase offsets in reverse order, we'll + // emit them for the primary base first). + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) + AddVCallAndVBaseOffsets(PrimaryBase, OffsetToTop, VBases); + + AddVBaseOffsets(RD, OffsetToTop, VBases); +} + +void VtableBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, + int64_t OffsetToTop, + VisitedVirtualBasesSetTy &VBases) { + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + // Add vbase offsets. + 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()); + + // Check if this is a virtual base that we haven't visited before. + if (I->isVirtual() && VBases.insert(BaseDecl)) { + // FIXME: We shouldn't use / 8 here. + uint64_t Offset = + OffsetToTop + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl) / 8; + + VCallAndVBaseOffsets.push_back(VtableComponent::MakeVBaseOffset(Offset)); + } + + // Check the base class looking for more vbase offsets. + AddVBaseOffsets(BaseDecl, OffsetToTop, VBases); + } +} + +void +VtableBuilder::AddMethod(const CXXMethodDecl *MD, + ReturnAdjustment ReturnAdjustment, + ThisAdjustment ThisAdjustment) { + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + assert(ReturnAdjustment.isEmpty() && + "Destructor can't have return adjustment!"); + // Add the 'this' pointer adjustments if necessary. + if (!ThisAdjustment.isEmpty()) { + ThisAdjustments.push_back(std::make_pair(Components.size(), + ThisAdjustment)); + ThisAdjustments.push_back(std::make_pair(Components.size() + 1, + ThisAdjustment)); + } + + // Add both the complete destructor and the deleting destructor. + Components.push_back(VtableComponent::MakeCompleteDtor(DD)); + Components.push_back(VtableComponent::MakeDeletingDtor(DD)); + } else { + // Add the return adjustment if necessary. + if (!ReturnAdjustment.isEmpty()) + ReturnAdjustments.push_back(std::make_pair(Components.size(), + ReturnAdjustment)); + + // Add the 'this' pointer adjustment if necessary. + if (!ThisAdjustment.isEmpty()) + ThisAdjustments.push_back(std::make_pair(Components.size(), + ThisAdjustment)); + + // Add the function. + Components.push_back(VtableComponent::MakeFunction(MD)); + } +} + +void +VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) { + const CXXRecordDecl *RD = Base.getBase(); + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + if (Layout.getPrimaryBaseWasVirtual()) + assert(false && "FIXME: Handle vbases here."); + else + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + AddMethods(BaseSubobject(PrimaryBase, Base.getBaseOffset()), PrimaryBases); + + if (!PrimaryBases.insert(PrimaryBase)) + assert(false && "Found a duplicate primary base!"); + } + + // Now go through all virtual member functions and add them. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(Base, MD); + + // Check if this virtual member function overrides a method in a primary + // base. If this is the case, and the return type doesn't require adjustment + // then we can just use the member function from the primary base. + if (const CXXMethodDecl *OverriddenMD = + OverridesMethodInPrimaryBase(MD, PrimaryBases)) { + if (ComputeReturnAdjustmentBaseOffset(Context, MD, + OverriddenMD).isEmpty()) + continue; + } + + // Check if this overrider needs a return adjustment. + FinalOverriders::BaseOffset ReturnAdjustmentOffset = + Overriders.getReturnAdjustmentOffset(Base, MD); + + ReturnAdjustment ReturnAdjustment = + ComputeReturnAdjustment(ReturnAdjustmentOffset); + + // Check if this overrider needs a 'this' pointer adjustment. + FinalOverriders::BaseOffset ThisAdjustmentOffset = + Overriders.getThisAdjustmentOffset(Base, MD); + + ThisAdjustment ThisAdjustment = ComputeThisAdjustment(ThisAdjustmentOffset); + + AddMethod(Overrider.Method, ReturnAdjustment, ThisAdjustment); + } +} + +void VtableBuilder::LayoutVtable(BaseSubobject Base) { + const CXXRecordDecl *RD = Base.getBase(); + assert(RD->isDynamicClass() && "class does not have a vtable!"); + + int64_t OffsetToTop = -(int64_t)Base.getBaseOffset() / 8; + + // Add vcall and vbase offsets for this vtable. + VisitedVirtualBasesSetTy VBases; + AddVCallAndVBaseOffsets(RD, OffsetToTop, VBases); + + // Reverse them and add them to the vtable components. + std::reverse(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end()); + Components.append(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end()); + VCallAndVBaseOffsets.clear(); + + // Add the offset to top. + // FIXME: This is not going to be right for construction vtables. + // FIXME: We should not use / 8 here. + Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop)); + + // Next, add the RTTI. + Components.push_back(VtableComponent::MakeRTTI(MostDerivedClass)); + + uint64_t AddressPoint = Components.size(); + + // Now go through all virtual member functions and add them. + PrimaryBasesSetTy PrimaryBases; + AddMethods(Base, PrimaryBases); + + // Record the address point. + AddressPoints.insert(std::make_pair(Base, AddressPoint)); + + // Record the address points for all primary bases. + for (PrimaryBasesSetTy::const_iterator I = PrimaryBases.begin(), + E = PrimaryBases.end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = *I; + + // We know that all the primary bases have the same offset as the base + // subobject. + BaseSubobject PrimaryBase(BaseDecl, Base.getBaseOffset()); + AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint)); + } + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + // Layout secondary vtables. + 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()); + + // Ignore bases that don't have a vtable. + if (!BaseDecl->isDynamicClass()) + continue; + + // Ignore the primary base. + if (BaseDecl == PrimaryBase) + continue; + + // Ignore virtual bases, we'll emit them later. + if (I->isVirtual()) + continue; + + // Get the base offset of this base. + uint64_t BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + // Layout this secondary vtable. + LayoutVtable(BaseSubobject(BaseDecl, BaseOffset)); + } + + // FIXME: Emit vtables for virtual bases here. +} + +/// dumpLayout - Dump the vtable layout. +void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { + + Out << "Vtable for '" << MostDerivedClass->getQualifiedNameAsString(); + Out << "' (" << Components.size() << " entries).\n"; + + // Iterate through the address points and insert them into a new map where + // they are keyed by the index and not the base object. + // 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) { + const BaseSubobject& Base = I->first; + uint64_t Index = I->second; + + AddressPointsByIndex.insert(std::make_pair(Index, Base)); + } + + unsigned NextReturnAdjustmentIndex = 0; + unsigned NextThisAdjustmentIndex = 0; + for (unsigned I = 0, E = Components.size(); I != E; ++I) { + uint64_t Index = I; + + if (AddressPointsByIndex.count(I)) { + if (AddressPointsByIndex.count(Index) == 1) { + const BaseSubobject &Base = AddressPointsByIndex.find(Index)->second; + + // FIXME: Instead of dividing by 8, we should be using CharUnits. + Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); + Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n"; + } else { + uint64_t BaseOffset = + AddressPointsByIndex.lower_bound(Index)->second.getBaseOffset(); + + // We store the class names in a set to get a stable order. + std::set<std::string> ClassNames; + for (std::multimap<uint64_t, BaseSubobject>::const_iterator I = + AddressPointsByIndex.lower_bound(Index), E = + AddressPointsByIndex.upper_bound(Index); I != E; ++I) { + assert(I->second.getBaseOffset() == BaseOffset && + "Invalid base offset!"); + const CXXRecordDecl *RD = I->second.getBase(); + ClassNames.insert(RD->getQualifiedNameAsString()); + } + + for (std::set<std::string>::const_iterator I = ClassNames.begin(), + E = ClassNames.end(); I != E; ++I) { + // FIXME: Instead of dividing by 8, we should be using CharUnits. + Out << " -- (" << *I; + Out << ", " << BaseOffset / 8 << ") vtable address --\n"; + } + } + } + + Out << llvm::format("%4d | ", I); + + const VtableComponent &Component = Components[I]; + + // Dump the component. + switch (Component.getKind()) { + // FIXME: Remove this default case. + default: + assert(false && "Unhandled component kind!"); + break; + + case VtableComponent::CK_VBaseOffset: + Out << "vbase_offset (" << Component.getVBaseOffset() << ")"; + break; + + case VtableComponent::CK_OffsetToTop: + Out << "offset_to_top (" << Component.getOffsetToTop() << ")"; + break; + + case VtableComponent::CK_RTTI: + Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI"; + break; + + case VtableComponent::CK_FunctionPointer: { + const CXXMethodDecl *MD = Component.getFunctionDecl(); + + std::string Str = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + Out << Str; + if (MD->isPure()) + Out << " [pure]"; + + // If this function pointer has a return adjustment, dump it. + if (NextReturnAdjustmentIndex < ReturnAdjustments.size() && + ReturnAdjustments[NextReturnAdjustmentIndex].first == I) { + const ReturnAdjustment Adjustment = + ReturnAdjustments[NextReturnAdjustmentIndex].second; + + Out << "\n [return adjustment: "; + Out << Adjustment.NonVirtual << " non-virtual"; + + if (Adjustment.VBaseOffsetOffset) + Out << ", " << Adjustment.VBaseOffsetOffset << " vbase offset offset"; + Out << ']'; + + NextReturnAdjustmentIndex++; + } + + // If this function pointer has a 'this' pointer adjustment, dump it. + if (NextThisAdjustmentIndex < ThisAdjustments.size() && + ThisAdjustments[NextThisAdjustmentIndex].first == I) { + const ThisAdjustment Adjustment = + ThisAdjustments[NextThisAdjustmentIndex].second; + + Out << "\n [this adjustment: "; + Out << Adjustment.NonVirtual << " non-virtual"; + + Out << ']'; + + NextThisAdjustmentIndex++; + } + + break; + } + + case VtableComponent::CK_CompleteDtorPointer: { + const CXXDestructorDecl *DD = Component.getDestructorDecl(); + + Out << DD->getQualifiedNameAsString() << "() [complete]"; + if (DD->isPure()) + Out << " [pure]"; + + break; + } + + case VtableComponent::CK_DeletingDtorPointer: { + const CXXDestructorDecl *DD = Component.getDestructorDecl(); + + Out << DD->getQualifiedNameAsString() << "() [deleting]"; + if (DD->isPure()) + Out << " [pure]"; + + break; + } + + } + + Out << '\n'; + } + +} + +} + +namespace { +class OldVtableBuilder { +public: /// Index_t - Vtable index type. typedef uint64_t Index_t; typedef std::vector<std::pair<GlobalDecl, @@ -57,10 +1288,11 @@ private: llvm::LLVMContext &VMContext; CodeGenModule &CGM; // Per-module state. - llvm::DenseMap<GlobalDecl, Index_t> VCall; + 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<GlobalDecl, Index_t> NonVirtualOffset; + llvm::DenseMap<const CXXMethodDecl *, Index_t> NonVirtualOffset; llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex; /// PureVirtualFunction - Points to __cxa_pure_virtual. @@ -180,6 +1412,196 @@ private: 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()->getNameAsCString(), + PrevU->getNameAsCString(), + U->getParent()->getNameAsCString(), + U->getNameAsCString()); + ForwardUnique[PrevU] = U; + return; + } + + // Not set, set it now + if (0) + printf("marking %s::%s %p override as %s::%s\n", + MD->getParent()->getNameAsCString(), + MD->getNameAsCString(), + (void*)MD, + U->getParent()->getNameAsCString(), + U->getNameAsCString()); + 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()->getNameAsCString(), + MD->getNameAsCString(), + (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)->getNameAsCString()); + 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) { @@ -193,7 +1615,7 @@ private: } public: - VtableBuilder(const CXXRecordDecl *MostDerivedClass, + OldVtableBuilder(const CXXRecordDecl *MostDerivedClass, const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm, bool build, CGVtableInfo::AddressPointsMapTy& AddressPoints) : BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l), @@ -209,6 +1631,8 @@ public: QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass); rtti = CGM.GetAddrOfRTTIDescriptor(ClassType); } + BuildUniqueOverriders(MostDerivedClass); + MergeForwarding(); } // getVtableComponents - Returns a reference to the vtable components. @@ -384,17 +1808,24 @@ public: // entry. Methods.AddMethod(GD); - VCallOffset[GD] = Offset/8; + VCallOffset[GD] = Offset/8 - CurrentVBaseOffset/8; + if (MorallyVirtual) { - Index_t &idx = VCall[GD]; + 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) { - NonVirtualOffset[GD] = CurrentVBaseOffset/8 - Offset/8; + VCallOffsetForVCall[UGD] = Offset/8; + NonVirtualOffset[UMD] = Offset/8 - CurrentVBaseOffset/8; idx = VCalls.size()+1; - VCalls.push_back(0); + VCalls.push_back(Offset/8 - CurrentVBaseOffset/8); D1(printf(" vcall for %s at %d with delta %d\n", dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(), - (int)-VCalls.size()-3, 0)); + (int)-VCalls.size()-3, (int)VCalls[idx-1])); } } } @@ -459,6 +1890,9 @@ public: } VCalls.clear(); VCall.clear(); + VCallOffsetForVCall.clear(); + VCallOffset.clear(); + NonVirtualOffset.clear(); } void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset, @@ -699,84 +2133,7 @@ public: }; } // end anonymous namespace -/// TypeConversionRequiresAdjustment - Returns whether conversion from a -/// derived type to a base type requires adjustment. -static bool -TypeConversionRequiresAdjustment(ASTContext &Ctx, - const CXXRecordDecl *DerivedDecl, - const CXXRecordDecl *BaseDecl) { - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/true); - if (!const_cast<CXXRecordDecl *>(DerivedDecl)-> - isDerivedFrom(const_cast<CXXRecordDecl *>(BaseDecl), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return false; - } - - // If we found a virtual base we always want to require adjustment. - if (Paths.getDetectedVirtual()) - return true; - - const CXXBasePath &Path = Paths.front(); - - for (size_t Start = 0, End = Path.size(); Start != End; ++Start) { - const CXXBasePathElement &Element = Path[Start]; - - // Check the base class offset. - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class); - - const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); - const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); - - if (Layout.getBaseClassOffset(Base) != 0) { - // This requires an adjustment. - return true; - } - } - - return false; -} - -static bool -TypeConversionRequiresAdjustment(ASTContext &Ctx, - QualType DerivedType, QualType BaseType) { - // Canonicalize the types. - QualType CanDerivedType = Ctx.getCanonicalType(DerivedType); - QualType CanBaseType = Ctx.getCanonicalType(BaseType); - - assert(CanDerivedType->getTypeClass() == CanBaseType->getTypeClass() && - "Types must have same type class!"); - - if (CanDerivedType == CanBaseType) { - // No adjustment needed. - return false; - } - - if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) { - CanDerivedType = RT->getPointeeType(); - CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType(); - } else if (const PointerType *PT = dyn_cast<PointerType>(CanDerivedType)) { - CanDerivedType = PT->getPointeeType(); - CanBaseType = cast<PointerType>(CanBaseType)->getPointeeType(); - } else { - assert(false && "Unexpected return type!"); - } - - if (CanDerivedType == CanBaseType) { - // No adjustment needed. - return false; - } - - const CXXRecordDecl *DerivedDecl = - cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl()); - - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl()); - - return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl); -} - -bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, +bool OldVtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, Index_t OverrideOffset, Index_t Offset, int64_t CurrentVBaseOffset) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); @@ -788,6 +2145,7 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, 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)) @@ -801,6 +2159,8 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, if (!Methods.getIndex(OGD, Index)) continue; + OGD2 = OGD; + // Get the original method, which we should be computing thunks, etc, // against. OGD = Methods.getOrigMethod(Index); @@ -812,8 +2172,8 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, OMD->getType()->getAs<FunctionType>()->getResultType(); // Check if we need a return type adjustment. - if (TypeConversionRequiresAdjustment(CGM.getContext(), ReturnType, - OverriddenReturnType)) { + if (!ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, + OMD).isEmpty()) { CanQualType &BaseReturnType = BaseReturnTypes[Index]; // Insert the base return type. @@ -824,26 +2184,39 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, 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(OGD)) { - Index_t &idx = VCall[OGD]; + if (MorallyVirtual || VCall.count(UMD)) { + + Index_t &idx = VCall[UMD]; if (idx == 0) { - NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8; - VCallOffset[GD] = OverrideOffset/8; + 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(0); + 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 { - NonVirtualOffset[GD] = NonVirtualOffset[OGD]; - VCallOffset[GD] = VCallOffset[OGD]; - VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8; + 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 = NonVirtualOffset[GD]; + 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); @@ -859,12 +2232,19 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, SavedAdjustments.push_back( std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); } - VCall[GD] = idx; return true; } - int64_t NonVirtualAdjustment = -VCallOffset[OGD] + OverrideOffset/8; + 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); @@ -880,7 +2260,7 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, return false; } -void VtableBuilder::AppendMethodsToVtable() { +void OldVtableBuilder::AppendMethodsToVtable() { if (!BuildVtable) { VtableComponents.insert(VtableComponents.end(), Methods.size(), (llvm::Constant *)0); @@ -948,13 +2328,13 @@ void VtableBuilder::AppendMethodsToVtable() { void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Itanium C++ ABI 2.5.2: - // The order of the virtual function pointers in a virtual table is the - // order of declaration of the corresponding member functions in the class. + // The order of the virtual function pointers in a virtual table is the + // order of declaration of the corresponding member functions in the class. // - // There is an entry for any virtual function declared in a class, - // whether it is a new function or overrides a base class function, - // unless it overrides a function from the primary base, and conversion - // between their return types does not require an adjustment. + // There is an entry for any virtual function declared in a class, + // whether it is a new function or overrides a base class function, + // unless it overrides a function from the primary base, and conversion + // between their return types does not require an adjustment. int64_t CurrentIndex = 0; @@ -972,7 +2352,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Collect all the primary bases, so we can check whether methods override // a method from the base. - llvm::SmallPtrSet<const CXXRecordDecl *, 5> PrimaryBases; + VtableBuilder::PrimaryBasesSetTy PrimaryBases; for (ASTRecordLayout::primary_base_info_iterator I = Layout.primary_base_begin(), E = Layout.primary_base_end(); I != E; ++I) @@ -988,51 +2368,33 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { if (!MD->isVirtual()) continue; - bool ShouldAddEntryForMethod = true; - // Check if this method overrides a method in the primary base. - for (CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(), - e = MD->end_overridden_methods(); i != e; ++i) { - const CXXMethodDecl *OverriddenMD = *i; - const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); - assert(OverriddenMD->isCanonicalDecl() && - "Should have the canonical decl of the overridden RD!"); - - if (PrimaryBases.count(OverriddenRD)) { - // Check if converting from the return type of the method to the - // return type of the overridden method requires conversion. - QualType ReturnType = - MD->getType()->getAs<FunctionType>()->getResultType(); - QualType OverriddenReturnType = - OverriddenMD->getType()->getAs<FunctionType>()->getResultType(); - - if (!TypeConversionRequiresAdjustment(CGM.getContext(), - ReturnType, OverriddenReturnType)) { - // This index is shared between the index in the vtable of the primary - // base class. - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - const CXXDestructorDecl *OverriddenDD = - cast<CXXDestructorDecl>(OverriddenMD); - - // Add both the complete and deleting entries. - MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = - getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); - MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = - getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); - } else { - MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD); - } + if (const CXXMethodDecl *OverriddenMD = + OverridesMethodInPrimaryBase(MD, PrimaryBases)) { + // Check if converting from the return type of the method to the + // return type of the overridden method requires conversion. + if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, + OverriddenMD).isEmpty()) { + // This index is shared between the index in the vtable of the primary + // base class. + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + const CXXDestructorDecl *OverriddenDD = + cast<CXXDestructorDecl>(OverriddenMD); - // We don't need to add an entry for this method. - ShouldAddEntryForMethod = false; - break; - } + // Add both the complete and deleting entries. + MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = + getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); + MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = + getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); + } else { + MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD); + } + + // We don't need to add an entry for this method. + continue; } } - if (!ShouldAddEntryForMethod) - continue; - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { if (MD->isImplicit()) { assert(!ImplicitVirtualDtor && @@ -1054,8 +2416,8 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { if (ImplicitVirtualDtor) { // Itanium C++ ABI 2.5.2: - // If a class has an implicitly-defined virtual destructor, - // its entries come after the declared virtual function pointers. + // If a class has an implicitly-defined virtual destructor, + // its entries come after the declared virtual function pointers. // Add the complete dtor. MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = @@ -1107,12 +2469,12 @@ CGVtableInfo::getAdjustments(GlobalDecl GD) { return 0; AddressPointsMapTy AddressPoints; - VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints); + OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints); D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); - for (VtableBuilder::SavedAdjustmentsVectorTy::iterator + for (OldVtableBuilder::SavedAdjustmentsVectorTy::iterator i = b.getSavedAdjustments().begin(), e = b.getSavedAdjustments().end(); i != e; i++) SavedAdjustments[i->first].push_back(i->second); @@ -1136,7 +2498,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, // FIXME: This seems expensive. Can we do a partial job to get // just this data. AddressPointsMapTy AddressPoints; - VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints); + OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints); D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -1150,6 +2512,12 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, } I = VirtualBaseClassIndicies.find(ClassPair); + // FIXME: The assertion below assertion currently fails with the old vtable + /// layout code if there is a non-virtual thunk adjustment in a vtable. + // Once the new layout is in place, this return should be removed. + if (I == VirtualBaseClassIndicies.end()) + return 0; + assert(I != VirtualBaseClassIndicies.end() && "Did not find index!"); return I->second; @@ -1168,6 +2536,13 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *LayoutClass, const CXXRecordDecl *RD, uint64_t Offset, AddressPointsMapTy& AddressPoints) { + if (GenerateDefinition && CGM.getLangOptions().DumpVtableLayouts && + LayoutClass == RD) { + VtableBuilder Builder(*this, RD); + + Builder.dumpLayout(llvm::errs()); + } + llvm::SmallString<256> OutName; if (LayoutClass != RD) CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8, @@ -1179,8 +2554,8 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); if (GV == 0 || CGM.getVtableInfo().AddressPoints[LayoutClass] == 0 || GV->isDeclaration()) { - VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition, - AddressPoints); + OldVtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition, + AddressPoints); D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index f0a5c64d2fdf..5a4f94e3e092 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -171,6 +171,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, CurFn = Fn; assert(CurFn->isDeclaration() && "Function already has body?"); + // Pass inline keyword to optimizer if it appears explicitly on any + // declaration. + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) + for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(), + RE = FD->redecls_end(); RI != RE; ++RI) + if (RI->isInlineSpecified()) { + Fn->addFnAttr(llvm::Attribute::InlineHint); + break; + } + llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn); // Create a marker to make it easy to insert allocas into the entryblock @@ -196,7 +206,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } // FIXME: Leaked. - CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args); + // CC info is ignored, hopefully? + CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args, + CC_Default, false); if (RetTy->isVoidType()) { // Void type; nothing to return. @@ -281,6 +293,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); PushCleanupBlock(DtorEpilogue); + InitializeVtablePtrs(DD->getParent()); + EmitStmt(S); CleanupBlockInfo Info = PopCleanupBlock(); @@ -431,7 +445,11 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock); EmitBlock(LHSTrue); + // Any temporaries created here are conditional. + BeginConditionalBranch(); EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); + EndConditionalBranch(); + return; } else if (CondBOp->getOpcode() == BinaryOperator::LOr) { // If we have "0 || X", simplify the code. "1 || X" would have constant @@ -454,7 +472,11 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse); EmitBlock(LHSFalse); + // Any temporaries created here are conditional. + BeginConditionalBranch(); EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); + EndConditionalBranch(); + return; } } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 30ad663771be..fb2e5fee7309 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -268,7 +268,7 @@ public: /// this behavior for branches? void EmitBranchThroughCleanup(llvm::BasicBlock *Dest); - /// StartConditionalBranch - Should be called before a conditional part of an + /// BeginConditionalBranch - Should be called before a conditional part of an /// expression is emitted. For example, before the RHS of the expression below /// is emitted: /// @@ -276,13 +276,16 @@ public: /// /// This is used to make sure that any temporaries created in the conditional /// branch are only destroyed if the branch is taken. - void StartConditionalBranch() { + void BeginConditionalBranch() { ++ConditionalBranchLevel; } - /// FinishConditionalBranch - Should be called after a conditional part of an + /// EndConditionalBranch - Should be called after a conditional part of an /// expression has been emitted. - void FinishConditionalBranch() { + void EndConditionalBranch() { + assert(ConditionalBranchLevel != 0 && + "Conditional branch mismatch!"); + --ConditionalBranchLevel; } @@ -472,7 +475,7 @@ public: const BlockInfo& Info, const Decl *OuterFuncDecl, llvm::DenseMap<const Decl*, llvm::Value*> ldm, - CharUnits &Size, uint64_t &Align, + CharUnits &Size, CharUnits &Align, llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls, bool &subBlockHasCopyDispose); @@ -569,6 +572,9 @@ public: const llvm::Type *ConvertTypeForMem(QualType T); const llvm::Type *ConvertType(QualType T); + const llvm::Type *ConvertType(const TypeDecl *T) { + return ConvertType(getContext().getTypeDeclType(T)); + } /// LoadObjCSelf - Load the value of self. This function is only valid while /// generating code for an Objective-C method. @@ -652,10 +658,15 @@ public: } /// CreateTempAlloca - This creates a alloca and inserts it into the entry - /// block. + /// block. The caller is responsible for setting an appropriate alignment on + /// the alloca. llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, const llvm::Twine &Name = "tmp"); + /// CreateMemTemp - Create a temporary memory object of the given type, with + /// appropriate alignment. + llvm::Value *CreateMemTemp(QualType T, const llvm::Twine &Name = "tmp"); + /// EvaluateExprAsBool - Perform the usual unary conversions on the specified /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *EvaluateExprAsBool(const Expr *E); @@ -732,11 +743,16 @@ public: /// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have /// virtual bases. llvm::Value *LoadCXXVTT(); + + /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a + /// complete class down to one of its virtual bases. + llvm::Value *GetAddressOfBaseOfCompleteClass(llvm::Value *Value, + bool IsVirtual, + const CXXRecordDecl *Derived, + const CXXRecordDecl *Base); /// GetAddressOfBaseClass - This function will add the necessary delta to the /// load of 'this' and returns address of the base class. - // FIXME. This currently only does a derived to non-virtual base conversion. - // Other kinds of conversions will come later. llvm::Value *GetAddressOfBaseClass(llvm::Value *Value, const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl, @@ -747,10 +763,9 @@ public: const CXXRecordDecl *DerivedClassDecl, bool NullCheckValue); - llvm::Value * - GetVirtualCXXBaseClassOffset(llvm::Value *This, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl); + llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl); void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, @@ -843,7 +858,8 @@ public: /// This function can be called with a null (unreachable) insert point. void EmitLocalBlockVarDecl(const VarDecl &D); - void EmitStaticBlockVarDecl(const VarDecl &D); + void EmitStaticBlockVarDecl(const VarDecl &D, + llvm::GlobalValue::LinkageTypes Linkage); /// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl. void EmitParmDecl(const VarDecl &D, llvm::Value *Arg); @@ -1005,12 +1021,18 @@ public: LValue EmitCastLValue(const CastExpr *E); LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E); - LValue EmitPointerToDataMemberLValue(const FieldDecl *Field); - llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field, - bool isUnion, unsigned CVRQualifiers); + unsigned CVRQualifiers); + + /// EmitLValueForFieldInitialization - Like EmitLValueForField, except that + /// if the Field is a reference, this will return the address of the reference + /// and not the address of the value stored in the reference. + LValue EmitLValueForFieldInitialization(llvm::Value* Base, + const FieldDecl* Field, + unsigned CVRQualifiers); + LValue EmitLValueForIvar(QualType ObjectTy, llvm::Value* Base, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers); @@ -1103,8 +1125,7 @@ public: /// EmitReferenceBindingToExpr - Emits a reference binding to the passed in /// expression. Will emit a temporary variable if E is not an LValue. - RValue EmitReferenceBindingToExpr(const Expr* E, QualType DestType, - bool IsInitializer = false); + RValue EmitReferenceBindingToExpr(const Expr* E, bool IsInitializer = false); //===--------------------------------------------------------------------===// // Expression Emission @@ -1135,6 +1156,10 @@ public: bool IgnoreResult = false, bool IsInitializer = false, bool RequiresGCollection = false); + /// EmitAggExprToLValue - Emit the computation of the specified expression of + /// aggregate type into a temporary LValue. + LValue EmitAggExprToLValue(const Expr *E); + /// EmitGCMemmoveCollectable - Emit special API for structs with object /// pointers. void EmitGCMemmoveCollectable(llvm::Value *DestPtr, llvm::Value *SrcPtr, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index cf504a7c2a0c..5a552c490ac6 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -20,6 +20,7 @@ #include "TargetInfo.h" #include "clang/CodeGen/CodeGenOptions.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/RecordLayout.h" @@ -131,6 +132,10 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const { } } + // This decl should have the same visibility as its parent. + if (const DeclContext *DC = D->getDeclContext()) + return getDeclVisibilityMode(cast<Decl>(DC)); + return getLangOptions().getVisibilityMode(); } @@ -254,34 +259,40 @@ void CodeGenModule::EmitAnnotations() { static CodeGenModule::GVALinkage GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, const LangOptions &Features) { - // Everything located semantically within an anonymous namespace is - // always internal. - if (FD->isInAnonymousNamespace()) - return CodeGenModule::GVA_Internal; + CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; - // "static" functions get internal linkage. - if (FD->getStorageClass() == FunctionDecl::Static && !isa<CXXMethodDecl>(FD)) - return CodeGenModule::GVA_Internal; + Linkage L = FD->getLinkage(); + if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus && + FD->getType()->getLinkage() == UniqueExternalLinkage) + L = UniqueExternalLinkage; - // The kind of external linkage this function will have, if it is not - // inline or static. - CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; - if (Context.getLangOptions().CPlusPlus) { - TemplateSpecializationKind TSK = FD->getTemplateSpecializationKind(); + switch (L) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: + return CodeGenModule::GVA_Internal; - if (TSK == TSK_ExplicitInstantiationDefinition) { - // If a function has been explicitly instantiated, then it should - // always have strong external linkage. + case ExternalLinkage: + switch (FD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + External = CodeGenModule::GVA_StrongExternal; + break; + + case TSK_ExplicitInstantiationDefinition: + // FIXME: explicit instantiation definitions should use weak linkage return CodeGenModule::GVA_StrongExternal; - } - - if (TSK == TSK_ImplicitInstantiation) + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ImplicitInstantiation: External = CodeGenModule::GVA_TemplateInstantiation; + break; + } } if (!FD->isInlined()) return External; - + if (!Features.CPlusPlus || FD->hasAttr<GNUInlineAttr>()) { // GNU or C99 inline semantics. Determine whether this symbol should be // externally visible. @@ -402,11 +413,13 @@ void CodeGenModule::SetInternalFunctionAttributes(const Decl *D, SetCommonAttributes(D, F); } -void CodeGenModule::SetFunctionAttributes(const FunctionDecl *FD, +void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction) { + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); + if (!IsIncompleteFunction) - SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(FD), F); + SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(GD), F); // Only a few attributes are set on declarations; these may later be // overridden by a definition. @@ -580,14 +593,24 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { // Static data may be deferred, but out-of-line static data members // cannot be. - if (VD->isInAnonymousNamespace()) - return true; - if (VD->getLinkage() == VarDecl::InternalLinkage) { + Linkage L = VD->getLinkage(); + if (L == ExternalLinkage && getContext().getLangOptions().CPlusPlus && + VD->getType()->getLinkage() == UniqueExternalLinkage) + L = UniqueExternalLinkage; + + switch (L) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: // Initializer has side effects? if (VD->getInit() && VD->getInit()->HasSideEffects(Context)) return false; return !(VD->isStaticDataMember() && VD->isOutOfLine()); + + case ExternalLinkage: + break; } + return false; } @@ -608,20 +631,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { const VarDecl *VD = cast<VarDecl>(Global); assert(VD->isFileVarDecl() && "Cannot emit local var decl as global."); - if (getLangOptions().CPlusPlus && !VD->getInit()) { - // In C++, if this is marked "extern", defer code generation. - if (VD->getStorageClass() == VarDecl::Extern || VD->isExternC()) - return; - - // If this is a declaration of an explicit specialization of a static - // data member in a class template, don't emit it. - if (VD->isStaticDataMember() && - VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) - return; - } - - // In C, if this isn't a definition, defer code generation. - if (!getLangOptions().CPlusPlus && !VD->getInit()) + if (VD->isThisDeclarationADefinition() != VarDecl::Definition) return; } @@ -715,8 +725,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, "", &getModule()); F->setName(MangledName); if (D.getDecl()) - SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F, - IsIncompleteFunction); + SetFunctionAttributes(D, F, IsIncompleteFunction); Entry = F; // This is the first use or definition of a mangled name. If there is a @@ -774,7 +783,7 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, } static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) { - if (!D->getType().isConstant(Context)) + if (!D->getType().isConstant(Context) && !D->getType()->isReferenceType()) return false; if (Context.getLangOptions().CPlusPlus && Context.getBaseElementType(D->getType())->getAs<RecordType>()) { @@ -941,16 +950,30 @@ CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) { static CodeGenModule::GVALinkage GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { - // Everything located semantically within an anonymous namespace is - // always internal. - if (VD->isInAnonymousNamespace()) + // If this is a static data member, compute the kind of template + // specialization. Otherwise, this variable is not part of a + // template. + TemplateSpecializationKind TSK = TSK_Undeclared; + if (VD->isStaticDataMember()) + TSK = VD->getTemplateSpecializationKind(); + + Linkage L = VD->getLinkage(); + if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus && + VD->getType()->getLinkage() == UniqueExternalLinkage) + L = UniqueExternalLinkage; + + switch (L) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: return CodeGenModule::GVA_Internal; - // Handle linkage for static data members. - if (VD->isStaticDataMember()) { - switch (VD->getTemplateSpecializationKind()) { + case ExternalLinkage: + switch (TSK) { case TSK_Undeclared: case TSK_ExplicitSpecialization: + + // FIXME: ExplicitInstantiationDefinition should be weak! case TSK_ExplicitInstantiationDefinition: return CodeGenModule::GVA_StrongExternal; @@ -959,22 +982,26 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { // Fall through to treat this like any other instantiation. case TSK_ImplicitInstantiation: - return CodeGenModule::GVA_TemplateInstantiation; + return CodeGenModule::GVA_TemplateInstantiation; } } - if (VD->getLinkage() == VarDecl::InternalLinkage) - return CodeGenModule::GVA_Internal; - return CodeGenModule::GVA_StrongExternal; } +CharUnits CodeGenModule::GetTargetTypeStoreSize(const llvm::Type *Ty) const { + return CharUnits::fromQuantity( + TheTargetData.getTypeStoreSizeInBits(Ty) / Context.getCharWidth()); +} + void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); bool NonConstInit = false; - if (D->getInit() == 0) { + const Expr *InitExpr = D->getAnyInitializer(); + + if (!InitExpr) { // This is a tentative definition; tentative definitions are // implicitly initialized with { 0 }. // @@ -987,10 +1014,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type"); Init = EmitNullConstant(D->getType()); } else { - Init = EmitConstantExpr(D->getInit(), D->getType()); + Init = EmitConstantExpr(InitExpr, D->getType()); if (!Init) { - QualType T = D->getInit()->getType(); + QualType T = InitExpr->getType(); if (getLangOptions().CPlusPlus) { EmitCXXGlobalVarDeclInitFunc(D); Init = EmitNullConstant(T); @@ -1058,7 +1085,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { if (!NonConstInit && DeclIsConstantGlobal(Context, D)) GV->setConstant(true); - GV->setAlignment(getContext().getDeclAlignInBytes(D)); + GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); // Set the llvm linkage type as appropriate. GVALinkage Linkage = GetLinkageForVariable(getContext(), D); @@ -1256,8 +1283,8 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); // Unique the name through the identifier table. - const char *AliaseeName = AA->getAliasee().c_str(); - AliaseeName = getContext().Idents.get(AliaseeName).getNameStart(); + const char *AliaseeName = + getContext().Idents.get(AA->getAliasee()).getNameStart(); // Create a reference to the named value. This ensures that it is emitted // if a deferred decl. @@ -1473,11 +1500,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { // String pointer. llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str()); - const char *Sect = 0; llvm::GlobalValue::LinkageTypes Linkage; bool isConstant; if (isUTF16) { - Sect = getContext().Target.getUnicodeStringSection(); // FIXME: why do utf strings get "_" labels instead of "L" labels? Linkage = llvm::GlobalValue::InternalLinkage; // Note: -fwritable-strings doesn't make unicode CFStrings writable, but @@ -1491,11 +1516,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, ".str"); - if (Sect) - GV->setSection(Sect); if (isUTF16) { - unsigned Align = getContext().getTypeAlign(getContext().ShortTy)/8; - GV->setAlignment(Align); + CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); + GV->setAlignment(Align.getQuantity()); } Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 81f39791fcd0..8280766c7035 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -53,6 +53,7 @@ namespace clang { class ObjCProtocolDecl; class ObjCEncodeExpr; class BlockExpr; + class CharUnits; class Decl; class Expr; class Stmt; @@ -238,10 +239,11 @@ public: BuildCovariantThunk(const GlobalDecl &GD, bool Extern, const CovariantThunkAdjustment &Adjustment); - /// GetCXXBaseClassOffset - Returns the offset from a derived class to its - /// base class. Returns null if the offset is 0. - llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl); + /// 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. @@ -346,6 +348,8 @@ public: llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, unsigned LineNo); + llvm::Constant *EmitPointerToDataMember(const FieldDecl *FD); + /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. /// \param OmitOnError - If true, then this error should only be emitted if no @@ -417,6 +421,10 @@ public: /// and type information of the given class. static llvm::GlobalVariable::LinkageTypes getVtableLinkage(const CXXRecordDecl *RD); + + /// GetTargetTypeStoreSize - Return the store size, in character units, of + /// the given LLVM type. + CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const; private: /// UniqueMangledName - Unique a name by (if necessary) inserting it into the @@ -443,7 +451,7 @@ private: /// SetFunctionAttributes - Set function attributes for a function /// declaration. - void SetFunctionAttributes(const FunctionDecl *FD, + void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 838f62a5cb1d..3c20934baf25 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -84,7 +84,7 @@ const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) { const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) { const llvm::Type *ResultType = ConvertTypeRecursive(T); - if (ResultType->isInteger(1)) + if (ResultType->isIntegerTy(1)) return llvm::IntegerType::get(getLLVMContext(), (unsigned)Context.getTypeSize(T)); // FIXME: Should assert that the llvm type and AST type has the same size. @@ -99,7 +99,7 @@ const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) { const llvm::Type *R = ConvertType(T); // If this is a non-bool type, don't map it. - if (!R->isInteger(1)) + if (!R->isIntegerTy(1)) return R; // Otherwise, return an integer of the target-specified size. @@ -399,18 +399,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { /// enum. const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { - // FIXME. This may have to move to a better place. - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - if (!i->isVirtual()) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - ConvertTagDeclType(Base); - } - } - } - // TagDecl's are not necessarily unique, instead use the (clang) // type connected to the decl. const Type *Key = @@ -422,8 +410,8 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { if (TDTI != TagDeclTypes.end()) return TDTI->second; - // If this is still a forward definition, just define an opaque type to use - // for this tagged decl. + // If this is still a forward declaration, just define an opaque + // type to use for this tagged decl. if (!TD->isDefinition()) { llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext()); TagDeclTypes.insert(std::make_pair(Key, ResultType)); @@ -446,6 +434,18 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { const RecordDecl *RD = cast<const RecordDecl>(TD); + // Force conversion of non-virtual base classes recursively. + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + ConvertTagDeclType(Base); + } + } + } + // Layout fields. CGRecordLayout *Layout = CGRecordLayoutBuilder::ComputeLayout(*this, RD); diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 7e342526e84b..87ba0bcfba1d 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -20,7 +20,7 @@ #include <vector> #include "CGCall.h" -#include "CGCXX.h" +#include "GlobalDecl.h" namespace llvm { class FunctionType; @@ -60,21 +60,24 @@ namespace CodeGen { /// LLVMType - The LLVMType corresponding to this record layout. const llvm::Type *LLVMType; - /// ContainsMemberPointer - Whether one of the fields in this record layout - /// is a member pointer, or a struct that contains a member pointer. - bool ContainsMemberPointer; + /// 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 ContainsMemberPointer) - : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer) { } + 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; } - bool containsMemberPointer() const { - return ContainsMemberPointer; + /// containsPointerToDataMember - Whether this struct contains pointers to + /// data members. + bool containsPointerToDataMember() const { + return ContainsPointerToDataMember; } }; @@ -187,6 +190,8 @@ private: public: /// getFunctionInfo - Get the function info for the specified function decl. + const CGFunctionInfo &getFunctionInfo(GlobalDecl GD); + const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD); const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD); const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD); @@ -195,6 +200,12 @@ public: const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D, CXXDtorType Type); + const CGFunctionInfo &getFunctionInfo(const CallArgList &Args, + const FunctionType *Ty) { + return getFunctionInfo(Ty->getResultType(), Args, + Ty->getCallConv(), Ty->getNoReturnAttr()); + } + // getFunctionInfo - Get the function info for a member function. const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, const FunctionProtoType *FTP); @@ -204,13 +215,16 @@ public: /// specified, the "C" calling convention will be used. const CGFunctionInfo &getFunctionInfo(QualType ResTy, const CallArgList &Args, - unsigned CallingConvention = 0); + CallingConv CC, + bool NoReturn); const CGFunctionInfo &getFunctionInfo(QualType ResTy, const FunctionArgList &Args, - unsigned CallingConvention = 0); + CallingConv CC, + bool NoReturn); const CGFunctionInfo &getFunctionInfo(QualType RetTy, const llvm::SmallVector<QualType, 16> &ArgTys, - unsigned CallingConvention = 0); + CallingConv CC, + bool NoReturn); public: // These are internal details of CGT that shouldn't be used externally. /// addFieldInfo - Assign field number to field FD. diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h index b054312a0185..b8a98d7c03b6 100644 --- a/lib/CodeGen/GlobalDecl.h +++ b/lib/CodeGen/GlobalDecl.h @@ -15,6 +15,10 @@ #ifndef CLANG_CODEGEN_GLOBALDECL_H #define CLANG_CODEGEN_GLOBALDECL_H +#include "CGCXX.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" + namespace clang { namespace CodeGen { diff --git a/lib/CodeGen/Makefile b/lib/CodeGen/Makefile index 108490b71d48..83cb36738709 100644 --- a/lib/CodeGen/Makefile +++ b/lib/CodeGen/Makefile @@ -15,7 +15,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangCodeGen BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include ifdef CLANG_VENDOR diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index d873cfec1bd7..a302225c7f77 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -26,6 +26,13 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" #include "CGVtable.h" + +#define MANGLE_CHECKER 0 + +#if MANGLE_CHECKER +#include <cxxabi.h> +#endif + using namespace clang; using namespace CodeGen; @@ -44,6 +51,8 @@ static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) { return MD; } + +static const unsigned UnknownArity = ~0U; /// CXXNameMangler - Manage the mangling of a single name. class CXXNameMangler { @@ -55,6 +64,8 @@ class CXXNameMangler { llvm::DenseMap<uintptr_t, unsigned> Substitutions; + ASTContext &getASTContext() const { return Context.getASTContext(); } + public: CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res) : Context(C), Out(Res), Structor(0), StructorType(0) { } @@ -65,6 +76,17 @@ public: const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { } +#if MANGLE_CHECKER + ~CXXNameMangler() { + if (Out.str()[0] == '\01') + return; + + int status = 0; + char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status); + assert(status == 0 && "Could not demangle mangled name!"); + free(result); + } +#endif llvm::raw_svector_ostream &getStream() { return Out; } void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z"); @@ -89,10 +111,19 @@ private: void addSubstitution(QualType T); void addSubstitution(uintptr_t Ptr); + void mangleUnresolvedScope(NestedNameSpecifier *Qualifier); + void mangleUnresolvedName(NestedNameSpecifier *Qualifier, + DeclarationName Name, + unsigned KnownArity = UnknownArity); + void mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); - void mangleUnqualifiedName(const NamedDecl *ND); + void mangleUnqualifiedName(const NamedDecl *ND) { + mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity); + } + void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name, + unsigned KnownArity); void mangleUnscopedName(const NamedDecl *ND); void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleSourceName(const IdentifierInfo *II); @@ -119,6 +150,11 @@ private: bool MangleReturnType); void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); + void mangleMemberExpr(const Expr *Base, bool IsArrow, + NestedNameSpecifier *Qualifier, + DeclarationName Name, + unsigned KnownArity); + void mangleCalledExpression(const Expr *E, unsigned KnownArity); void mangleExpression(const Expr *E); void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); @@ -171,14 +207,14 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { isInExternCSystemHeader(D->getLocation())) return false; - // Variables at global scope are not mangled. + // Variables at global scope with non-internal linkage are not mangled if (!FD) { const DeclContext *DC = D->getDeclContext(); // Check for extern variable declared locally. if (isa<FunctionDecl>(DC) && D->hasLinkage()) while (!DC->isNamespace() && !DC->isTranslationUnit()) DC = DC->getParent(); - if (DC->isTranslationUnit()) + if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage) return false; } @@ -199,13 +235,10 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) { return; } - // <mangled-name> ::= _Z [L] <encoding> + // <mangled-name> ::= _Z <encoding> // ::= <data name> // ::= <special-name> Out << Prefix; - if (D->getLinkage() == NamedDecl::InternalLinkage) // match gcc behavior - Out << 'L'; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) mangleFunctionEncoding(FD); else @@ -367,6 +400,13 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { if (mangleSubstitution(ND)) return; + // <template-template-param> ::= <template-param> + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(ND)) { + mangleTemplateParameter(TTP->getIndex()); + return; + } + mangleUnscopedName(ND->getTemplatedDecl()); addSubstitution(ND); } @@ -401,28 +441,69 @@ void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) { Out << '_'; } -void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { +void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) { + Qualifier = getASTContext().getCanonicalNestedNameSpecifier(Qualifier); + switch (Qualifier->getKind()) { + case NestedNameSpecifier::Global: + // nothing + break; + case NestedNameSpecifier::Namespace: + mangleName(Qualifier->getAsNamespace()); + break; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + mangleType(QualType(Qualifier->getAsType(), 0)); + break; + case NestedNameSpecifier::Identifier: + mangleUnresolvedScope(Qualifier->getPrefix()); + mangleSourceName(Qualifier->getAsIdentifier()); + break; + } +} + +/// Mangles a name which was not resolved to a specific entity. +void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *Qualifier, + DeclarationName Name, + unsigned KnownArity) { + if (Qualifier) + mangleUnresolvedScope(Qualifier); + // FIXME: ambiguity of unqualified lookup with :: + + mangleUnqualifiedName(0, Name, KnownArity); +} + +void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, + DeclarationName Name, + unsigned KnownArity) { // <unqualified-name> ::= <operator-name> // ::= <ctor-dtor-name> // ::= <source-name> - DeclarationName Name = ND->getDeclName(); switch (Name.getNameKind()) { case DeclarationName::Identifier: { + if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { + // We must avoid conflicts between internally- and externally- + // linked variable declaration names in the same TU. + // This naming convention is the same as that followed by GCC, though it + // shouldn't actually matter. + if (ND && isa<VarDecl>(ND) && ND->getLinkage() == InternalLinkage && + ND->getDeclContext()->isFileContext()) + Out << 'L'; + + mangleSourceName(II); + break; + } + + // Otherwise, an anonymous entity. We must have a declaration. + assert(ND && "mangling empty name without declaration"); + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { if (NS->isAnonymousNamespace()) { - // This is how gcc mangles these names. It's apparently - // always '1', no matter how many different anonymous - // namespaces appear in a context. + // This is how gcc mangles these names. Out << "12_GLOBAL__N_1"; break; } } - if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { - mangleSourceName(II); - break; - } - // We must have an anonymous struct. const TagDecl *TD = cast<TagDecl>(ND); if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) { @@ -484,13 +565,18 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { break; case DeclarationName::CXXOperatorName: { - unsigned Arity = cast<FunctionDecl>(ND)->getNumParams(); + unsigned Arity; + if (ND) { + Arity = cast<FunctionDecl>(ND)->getNumParams(); - // If we have a C++ member function, we need to include the 'this' pointer. - // FIXME: This does not make sense for operators that are static, but their - // names stay the same regardless of the arity (operator new for instance). - if (isa<CXXMethodDecl>(ND)) - Arity++; + // If we have a C++ member function, we need to include the 'this' pointer. + // FIXME: This does not make sense for operators that are static, but their + // names stay the same regardless of the arity (operator new for instance). + if (isa<CXXMethodDecl>(ND)) + Arity++; + } else + Arity = KnownArity; + mangleOperatorName(Name.getCXXOverloadedOperator(), Arity); break; } @@ -596,15 +682,21 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { // <template-prefix> ::= <prefix> <template unqualified-name> // ::= <template-param> // ::= <substitution> + // <template-template-param> ::= <template-param> + // <substitution> if (mangleSubstitution(ND)) return; - // FIXME: <template-param> + // <template-template-param> ::= <template-param> + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(ND)) { + mangleTemplateParameter(TTP->getIndex()); + return; + } manglePrefix(ND->getDeclContext()); mangleUnqualifiedName(ND->getTemplatedDecl()); - addSubstitution(ND); } @@ -1013,7 +1105,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) { dyn_cast<TemplateSpecializationType>(QTy)) { if (!mangleSubstitution(QualType(TST, 0))) { TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl(); - + assert(TD && "FIXME: Support dependent template names"); mangleTemplatePrefix(TD); mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); addSubstitution(QualType(TST, 0)); @@ -1049,23 +1141,151 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T, } +void CXXNameMangler::mangleCalledExpression(const Expr *E, unsigned Arity) { + if (E->getType() != getASTContext().OverloadTy) + mangleExpression(E); + // propagate arity to dependent overloads? + + llvm::PointerIntPair<OverloadExpr*,1> R + = OverloadExpr::find(const_cast<Expr*>(E)); + if (R.getInt()) + Out << "an"; // & + const OverloadExpr *Ovl = R.getPointer(); + if (const UnresolvedMemberExpr *ME = dyn_cast<UnresolvedMemberExpr>(Ovl)) { + mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(), + ME->getMemberName(), Arity); + return; + } + + mangleUnresolvedName(Ovl->getQualifier(), Ovl->getName(), Arity); +} + +/// Mangles a member expression. Implicit accesses are not handled, +/// but that should be okay, because you shouldn't be able to +/// make an implicit access in a function template declaration. +/// +/// The standard ABI does not describe how member expressions should +/// be mangled, so this is very unstandardized. We mangle as if it +/// were a binary operator, except that the RHS is mangled as an +/// abstract name. +/// +/// The standard ABI also does not assign a mangling to the dot +/// operator, so we arbitrarily select 'me'. +void CXXNameMangler::mangleMemberExpr(const Expr *Base, + bool IsArrow, + NestedNameSpecifier *Qualifier, + DeclarationName Member, + unsigned Arity) { + Out << (IsArrow ? "pt" : "me"); + mangleExpression(Base); + mangleUnresolvedName(Qualifier, Member, Arity); +} + void CXXNameMangler::mangleExpression(const Expr *E) { // <expression> ::= <unary operator-name> <expression> - // ::= <binary operator-name> <expression> <expression> - // ::= <trinary operator-name> <expression> <expression> <expression> - // ::= cl <expression>* E # call + // ::= <binary operator-name> <expression> <expression> + // ::= <trinary operator-name> <expression> <expression> <expression> + // ::= cl <expression>* E # call // ::= cv <type> expression # conversion with one argument // ::= cv <type> _ <expression>* E # conversion with a different number of arguments - // ::= st <type> # sizeof (a type) + // ::= st <type> # sizeof (a type) // ::= at <type> # alignof (a type) // ::= <template-param> // ::= <function-param> // ::= sr <type> <unqualified-name> # dependent name // ::= sr <type> <unqualified-name> <template-args> # dependent template-id // ::= sZ <template-param> # size of a parameter pack - // ::= <expr-primary> + // ::= <expr-primary> + // <expr-primary> ::= L <type> <value number> E # integer literal + // ::= L <type <value float> E # floating literal + // ::= L <mangled-name> E # external name switch (E->getStmtClass()) { - default: assert(false && "Unhandled expression kind!"); + default: + llvm_unreachable("unexpected statement kind"); + break; + + case Expr::CallExprClass: { + const CallExpr *CE = cast<CallExpr>(E); + Out << "cl"; + mangleCalledExpression(CE->getCallee(), CE->getNumArgs()); + for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I) + mangleExpression(CE->getArg(I)); + Out << "E"; + break; + } + + case Expr::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), ME->getMemberDecl()->getDeclName(), + UnknownArity); + break; + } + + case Expr::UnresolvedMemberExprClass: { + const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), ME->getMemberName(), + UnknownArity); + break; + } + + case Expr::CXXDependentScopeMemberExprClass: { + const CXXDependentScopeMemberExpr *ME + = cast<CXXDependentScopeMemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), ME->getMember(), + UnknownArity); + break; + } + + case Expr::UnresolvedLookupExprClass: { + // The ABI doesn't cover how to mangle overload sets, so we mangle + // using something as close as possible to the original lookup + // expression. + const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E); + mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), UnknownArity); + break; + } + + case Expr::CXXUnresolvedConstructExprClass: { + const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E); + unsigned N = CE->arg_size(); + + Out << "cv"; + mangleType(CE->getType()); + if (N != 1) Out << "_"; + for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); + if (N != 1) Out << "E"; + break; + } + + case Expr::CXXTemporaryObjectExprClass: + case Expr::CXXConstructExprClass: { + const CXXConstructExpr *CE = cast<CXXConstructExpr>(E); + unsigned N = CE->getNumArgs(); + + Out << "cv"; + mangleType(CE->getType()); + if (N != 1) Out << "_"; + for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); + if (N != 1) Out << "E"; + break; + } + + case Expr::SizeOfAlignOfExprClass: { + const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E); + if (SAE->isSizeOf()) Out << "s"; + else Out << "a"; + if (SAE->isArgumentType()) { + Out << "t"; + mangleType(SAE->getArgumentType()); + } else { + Out << "z"; + mangleExpression(SAE->getArgumentExpr()); + } + break; + } case Expr::UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(E); @@ -1082,7 +1302,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { mangleExpression(BO->getLHS()); mangleExpression(BO->getRHS()); break; - } + } case Expr::ConditionalOperatorClass: { const ConditionalOperator *CO = cast<ConditionalOperator>(E); @@ -1093,6 +1313,24 @@ void CXXNameMangler::mangleExpression(const Expr *E) { break; } + case Expr::ImplicitCastExprClass: { + mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr()); + break; + } + + case Expr::CStyleCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: + case Expr::CXXFunctionalCastExprClass: { + const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E); + Out << "cv"; + mangleType(ECE->getType()); + mangleExpression(ECE->getSubExpr()); + break; + } + case Expr::CXXOperatorCallExprClass: { const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E); unsigned NumArgs = CE->getNumArgs(); @@ -1139,6 +1377,20 @@ void CXXNameMangler::mangleExpression(const Expr *E) { break; } + case Expr::FloatingLiteralClass: { + const FloatingLiteral *FL = cast<FloatingLiteral>(E); + Out << "L"; + mangleType(FL->getType()); + + // TODO: avoid this copy with careful stream management. + llvm::SmallVector<char,20> Buffer; + FL->getValue().bitcastToAPInt().toString(Buffer, 16, false); + Out.write(Buffer.data(), Buffer.size()); + + Out << "E"; + break; + } + case Expr::IntegerLiteralClass: mangleIntegerLiteral(E->getType(), llvm::APSInt(cast<IntegerLiteral>(E)->getValue())); @@ -1216,6 +1468,8 @@ void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) { mangleType(A.getAsType()); break; case TemplateArgument::Template: + assert(A.getAsTemplate().getAsTemplateDecl() && + "FIXME: Support dependent template names"); mangleName(A.getAsTemplate().getAsTemplateDecl()); break; case TemplateArgument::Expression: diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 4454662a9304..a7c0caa299e7 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -271,6 +271,10 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, if (CodeGenFunction::hasAggregateLLVMType(Ty)) { return ABIArgInfo::getIndirect(0); } else { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } @@ -321,6 +325,9 @@ class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { public: X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p) :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {} + + void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &CGM) const; }; } @@ -358,6 +365,8 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, const RecordType *RT = Ty->getAs<RecordType>(); if (!RT) return false; + // FIXME: Traverse bases here too. + // Structure types are passed in register if all fields would be // passed in a register. for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(), @@ -404,7 +413,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, return ABIArgInfo::getDirect(); } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - if (const RecordType *RT = RetTy->getAsStructureType()) { + if (const RecordType *RT = RetTy->getAs<RecordType>()) { // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. if (hasNonTrivialDestructorOrCopyConstructor(RT)) @@ -463,6 +472,10 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, return ABIArgInfo::getIndirect(0); } else { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) + RetTy = EnumTy->getDecl()->getIntegerType(); + return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } @@ -484,10 +497,16 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, // FIXME: Set alignment on indirect arguments. if (CodeGenFunction::hasAggregateLLVMType(Ty)) { // Structures with flexible arrays are always indirect. - if (const RecordType *RT = Ty->getAsStructureType()) + if (const RecordType *RT = Ty->getAs<RecordType>()) { + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are always indirect. + if (hasNonTrivialDestructorOrCopyConstructor(RT)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (RT->getDecl()->hasFlexibleArrayMember()) return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context)); + } // Ignore empty structs. if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0) @@ -503,6 +522,9 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context)); } else { + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } @@ -532,6 +554,20 @@ llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return AddrTyped; } +void X86_32TargetCodeGenInfo::SetTargetAttributes(const Decl *D, + llvm::GlobalValue *GV, + CodeGen::CodeGenModule &CGM) const { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) { + // Get the LLVM function. + llvm::Function *Fn = cast<llvm::Function>(GV); + + // Now add the 'alignstack' attribute with a value of 16. + Fn->addFnAttr(llvm::Attribute::constructStackAlignmentFromInt(16)); + } + } +} + namespace { /// X86_64ABIInfo - The X86_64 ABI information. class X86_64ABIInfo : public ABIInfo { @@ -927,6 +963,11 @@ ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty, if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) { // Integer and pointer types will end up in a general purpose // register. + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + if (Ty->isIntegralType() || Ty->hasPointerRepresentation()) return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); @@ -948,9 +989,14 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, ASTContext &Context) const { // If this is a scalar LLVM value then assume LLVM will pass it in the right // place naturally. - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) + if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty); @@ -1319,14 +1365,14 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); const llvm::Type *TyLo = ST->getElementType(0); const llvm::Type *TyHi = ST->getElementType(1); - assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) && + assert((TyLo->isFloatingPointTy() ^ TyHi->isFloatingPointTy()) && "Unexpected ABI info for mixed regs"); const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); - llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr; - llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr; + llvm::Value *RegLoAddr = TyLo->isFloatingPointTy() ? FPAddr : GPAddr; + llvm::Value *RegHiAddr = TyLo->isFloatingPointTy() ? GPAddr : FPAddr; llvm::Value *V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo)); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); @@ -1526,9 +1572,14 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context, llvm::LLVMContext &VMContext) const { - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) + if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } // Ignore empty records. if (isEmptyRecord(Context, Ty, true)) @@ -1577,9 +1628,9 @@ static bool isIntegerLikeType(QualType Ty, if (Ty->getAs<BuiltinType>() || Ty->isPointerType()) return true; - // Complex types "should" be ok by the definition above, but they are not. - if (Ty->isAnyComplexType()) - return false; + // Small complex integer types are "integer like". + if (const ComplexType *CT = Ty->getAs<ComplexType>()) + return isIntegerLikeType(CT->getElementType(), Context, VMContext); // Single element and zero sized arrays should be allowed, by the definition // above, but they are not. @@ -1603,30 +1654,30 @@ static bool isIntegerLikeType(QualType Ty, i != e; ++i, ++idx) { const FieldDecl *FD = *i; - // Check if this field is at offset 0. - uint64_t Offset = Layout.getFieldOffset(idx); - if (Offset != 0) { - // Allow padding bit-fields, but only if they are all at the end of the - // structure (despite the wording above, this matches gcc). - if (FD->isBitField() && - !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { - for (; i != e; ++i) - if (!i->isBitField() || - i->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) - return false; - - // All remaining fields are padding, allow this. - return true; - } + // Bit-fields are not addressable, we only need to verify they are "integer + // like". We still have to disallow a subsequent non-bitfield, for example: + // struct { int : 0; int x } + // is non-integer like according to gcc. + if (FD->isBitField()) { + if (!RD->isUnion()) + HadField = true; - return false; + if (!isIntegerLikeType(FD->getType(), Context, VMContext)) + return false; + + continue; } + // Check if this field is at offset 0. + if (Layout.getFieldOffset(idx) != 0) + return false; + if (!isIntegerLikeType(FD->getType(), Context, VMContext)) return false; - // Only allow at most one field in a structure. Again this doesn't match the - // wording above, but follows gcc. + // Only allow at most one field in a structure. This doesn't match the + // wording above, but follows gcc in situations with a field following an + // empty structure. if (!RD->isUnion()) { if (HadField) return false; @@ -1644,15 +1695,28 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); - if (!CodeGenFunction::hasAggregateLLVMType(RetTy)) + if (!CodeGenFunction::hasAggregateLLVMType(RetTy)) { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) + RetTy = EnumTy->getDecl()->getIntegerType(); + return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } // Are we following APCS? if (getABIKind() == APCS) { if (isEmptyRecord(Context, RetTy, false)) return ABIArgInfo::getIgnore(); + // Complex types are all returned as packed integers. + // + // FIXME: Consider using 2 x vector types if the back end handles them + // correctly. + if (RetTy->isAnyComplexType()) + return ABIArgInfo::getCoerce(llvm::IntegerType::get( + VMContext, Context.getTypeSize(RetTy))); + // Integer like structures are returned in r0. if (isIntegerLikeType(RetTy, Context, VMContext)) { // Return in the smallest viable integer type. @@ -1721,6 +1785,10 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy, } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { return ABIArgInfo::getIndirect(0); } else { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) + RetTy = EnumTy->getDecl()->getIntegerType(); + return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 852a018e10f4..15df767d9707 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -50,8 +50,8 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName), Host(0), - CCCIsCXX(false), CCCEcho(false), CCCPrintBindings(false), - CCCGenericGCCName("gcc"), CCCUseClang(true), + CCCGenericGCCName("gcc"), CCCIsCXX(false), CCCEcho(false), + CCCPrintBindings(false), CheckInputsExist(true), CCCUseClang(true), CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true), SuppressMissingInputWarning(false) { if (IsProduction) { @@ -158,10 +158,8 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { llvm::Triple::ArchType Arch = llvm::Triple(Split.first, "", "").getArch(); - if (Arch == llvm::Triple::UnknownArch) { - Diag(clang::diag::err_drv_invalid_arch_name) << Arch; - continue; - } + if (Arch == llvm::Triple::UnknownArch) + Diag(clang::diag::err_drv_invalid_arch_name) << Split.first; CCCClangArchs.insert(Arch); } @@ -579,10 +577,9 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { Ty = InputType; } - // Check that the file exists. It isn't clear this is worth doing, since - // the tool presumably does this anyway, and this just adds an extra stat - // to the equation, but this is gcc compatible. - if (memcmp(Value, "-", 2) != 0 && !llvm::sys::Path(Value).exists()) + // Check that the file exists, if enabled. + if (CheckInputsExist && memcmp(Value, "-", 2) != 0 && + !llvm::sys::Path(Value).exists()) Diag(clang::diag::err_drv_no_such_file) << A->getValue(Args); else Inputs.push_back(std::make_pair(Ty, A)); @@ -625,6 +622,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler. } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) || + (FinalPhaseArg = Args.getLastArg(options::OPT_rewrite_objc)) || (FinalPhaseArg = Args.getLastArg(options::OPT__analyze, options::OPT__analyze_auto)) || (FinalPhaseArg = Args.getLastArg(options::OPT_emit_ast)) || @@ -745,6 +743,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, if (Args.hasArg(options::OPT_fsyntax_only)) { return new CompileJobAction(Input, types::TY_Nothing); + } else if (Args.hasArg(options::OPT_rewrite_objc)) { + return new CompileJobAction(Input, types::TY_RewrittenObjC); } else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) { return new AnalyzeJobAction(Input, types::TY_Plist); } else if (Args.hasArg(options::OPT_emit_ast)) { @@ -866,6 +866,44 @@ void Driver::BuildJobs(Compilation &C) const { } } +static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, + const JobAction *JA, + const ActionList *&Inputs) { + const Tool *ToolForJob = 0; + + // See if we should look for a compiler with an integrated assembler. We match + // bottom up, so what we are actually looking for is an assembler job with a + // compiler input. + if (C.getArgs().hasArg(options::OPT_integrated_as, + options::OPT_no_integrated_as, + TC->IsIntegratedAssemblerDefault()) && + !C.getArgs().hasArg(options::OPT_save_temps) && + isa<AssembleJobAction>(JA) && + Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) { + const Tool &Compiler = TC->SelectTool(C,cast<JobAction>(**Inputs->begin())); + if (Compiler.hasIntegratedAssembler()) { + Inputs = &(*Inputs)[0]->getInputs(); + ToolForJob = &Compiler; + } + } + + // Otherwise use the tool for the current job. + if (!ToolForJob) + ToolForJob = &TC->SelectTool(C, *JA); + + // See if we should use an integrated preprocessor. We do so when we have + // exactly one input, since this is the only use case we care about + // (irrelevant since we don't support combine yet). + if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin()) && + !C.getArgs().hasArg(options::OPT_no_integrated_cpp) && + !C.getArgs().hasArg(options::OPT_traditional_cpp) && + !C.getArgs().hasArg(options::OPT_save_temps) && + ToolForJob->hasIntegratedCPP()) + Inputs = &(*Inputs)[0]->getInputs(); + + return *ToolForJob; +} + void Driver::BuildJobsForAction(Compilation &C, const Action *A, const ToolChain *TC, @@ -906,21 +944,10 @@ void Driver::BuildJobsForAction(Compilation &C, return; } - const JobAction *JA = cast<JobAction>(A); - const Tool &T = TC->SelectTool(C, *JA); - - // See if we should use an integrated preprocessor. We do so when we have - // exactly one input, since this is the only use case we care about - // (irrelevant since we don't support combine yet). const ActionList *Inputs = &A->getInputs(); - if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin())) { - if (!C.getArgs().hasArg(options::OPT_no_integrated_cpp) && - !C.getArgs().hasArg(options::OPT_traditional_cpp) && - !C.getArgs().hasArg(options::OPT_save_temps) && - T.hasIntegratedCPP()) { - Inputs = &(*Inputs)[0]->getInputs(); - } - } + + const JobAction *JA = cast<JobAction>(A); + const Tool &T = SelectToolForJob(C, TC, JA, Inputs); // Only use pipes when there is exactly one input. bool TryToUsePipeInput = Inputs->size() == 1 && T.acceptsPipedInput(); @@ -1147,8 +1174,10 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, return false; } - // Always use clang for precompiling and AST generation, regardless of archs. - if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST) + // Always use clang for precompiling, AST generation, and rewriting, + // regardless of archs. + if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST || + JA.getType() == types::TY_RewrittenObjC) return true; // Finally, don't use clang if this isn't one of the user specified archs to diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp index ed73b17d75f1..18bb78659305 100644 --- a/lib/Driver/HostInfo.cpp +++ b/lib/Driver/HostInfo.cpp @@ -106,7 +106,7 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_arch)) { // The gcc driver behavior with multiple -arch flags wasn't consistent for // things which rely on a default architecture. We just use the last -arch - // to find the default tool chain (assuming it is valid.. + // to find the default tool chain (assuming it is valid). Arch = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args)); // If it was invalid just use the host, we will reject this command line @@ -146,10 +146,10 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args, // If we recognized the arch, match it to the toolchains we support. 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, - false); + 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, true); + TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion); else TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple); } @@ -159,8 +159,7 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args, // Unknown Host Info -/// UnknownHostInfo - Generic host information to use for unknown -/// hosts. +/// UnknownHostInfo - Generic host information to use for unknown hosts. class UnknownHostInfo : public HostInfo { /// Cache of tool chains we have created. mutable llvm::StringMap<ToolChain*> ToolChains; diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile index dbacf8be0141..371bda781c67 100644 --- a/lib/Driver/Makefile +++ b/lib/Driver/Makefile @@ -10,7 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangDriver BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index a9c6a68ceb8a..a7cd711df1bc 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -31,20 +31,12 @@ using namespace clang::driver::toolchains; /// Darwin - Darwin tool chain for i386 and x86_64. Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&_DarwinVersion)[3], bool _IsIPhoneOS) - : ToolChain(Host, Triple), - IsIPhoneOS(_IsIPhoneOS) + const unsigned (&_DarwinVersion)[3]) + : ToolChain(Host, Triple), TargetInitialized(false) { - DarwinVersion[0] = _DarwinVersion[0]; - DarwinVersion[1] = _DarwinVersion[1]; - DarwinVersion[2] = _DarwinVersion[2]; - llvm::raw_string_ostream(MacosxVersionMin) - << "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.' - << DarwinVersion[1]; - - // FIXME: Lift default up. - IPhoneOSVersionMin = "3.0"; + << "10." << std::max(0, (int)_DarwinVersion[0] - 4) << '.' + << _DarwinVersion[1]; } // FIXME: Can we tablegen this? @@ -112,8 +104,8 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const { DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, const unsigned (&DarwinVersion)[3], - const unsigned (&_GCCVersion)[3], bool IsIPhoneOS) - : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS) + const unsigned (&_GCCVersion)[3]) + : Darwin(Host, Triple, DarwinVersion) { GCCVersion[0] = _GCCVersion[0]; GCCVersion[1] = _GCCVersion[1]; @@ -245,8 +237,7 @@ void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args, void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - unsigned MacosxVersionMin[3]; - getMacosxVersionMin(Args, MacosxVersionMin); + // Note that this routine is only used for targetting OS X. // Derived from libgcc and lib specs but refactored. if (Args.hasArg(options::OPT_static)) { @@ -256,7 +247,7 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args, CmdArgs.push_back("-lgcc_eh"); } else if (Args.hasArg(options::OPT_miphoneos_version_min_EQ)) { // Derived from darwin_iphoneos_libgcc spec. - if (isIPhoneOS()) { + if (isTargetIPhoneOS()) { CmdArgs.push_back("-lgcc_s.1"); } else { CmdArgs.push_back("-lgcc_s.10.5"); @@ -266,20 +257,20 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args, options::OPT_fno_exceptions) || Args.hasArg(options::OPT_fgnu_runtime)) { // FIXME: This is probably broken on 10.3? - if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + if (isMacosxVersionLT(10, 5)) CmdArgs.push_back("-lgcc_s.10.4"); - else if (isMacosxVersionLT(MacosxVersionMin, 10, 6)) + else if (isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lgcc_s.10.5"); } else { - if (isMacosxVersionLT(MacosxVersionMin, 10, 3, 9)) + if (isMacosxVersionLT(10, 3, 9)) ; // Do nothing. - else if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + else if (isMacosxVersionLT(10, 5)) CmdArgs.push_back("-lgcc_s.10.4"); - else if (isMacosxVersionLT(MacosxVersionMin, 10, 6)) + else if (isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lgcc_s.10.5"); } - if (isIPhoneOS() || isMacosxVersionLT(MacosxVersionMin, 10, 6)) { + if (isTargetIPhoneOS() || isMacosxVersionLT(10, 6)) { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("-lSystem"); } else { @@ -290,9 +281,8 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args, } DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3], - bool IsIPhoneOS) - : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS) + const unsigned (&DarwinVersion)[3]) + : Darwin(Host, Triple, DarwinVersion) { // We expect 'as', 'ld', etc. to be adjacent to our install dir. getProgramPaths().push_back(getDriver().Dir); @@ -325,7 +315,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // Select the dynamic runtime library and the target specific static library. const char *DarwinStaticLib = 0; - if (isIPhoneOS()) { + if (isTargetIPhoneOS()) { CmdArgs.push_back("-lgcc_s.1"); // We may need some static functions for armv6/thumb which are required to @@ -333,20 +323,17 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, if (getDarwinArchName(Args) == "armv6") DarwinStaticLib = "libclang_rt.armv6.a"; } else { - unsigned MacosxVersionMin[3]; - getMacosxVersionMin(Args, MacosxVersionMin); - // The dynamic runtime library was merged with libSystem for 10.6 and // beyond; only 10.4 and 10.5 need an additional runtime library. - if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + if (isMacosxVersionLT(10, 5)) CmdArgs.push_back("-lgcc_s.10.4"); - else if (isMacosxVersionLT(MacosxVersionMin, 10, 6)) + else if (isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lgcc_s.10.5"); // For OS X, we only need a static runtime library when targetting 10.4, to // provide versions of the static functions which were omitted from // 10.4.dylib. - if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + if (isMacosxVersionLT(10, 5)) DarwinStaticLib = "libclang_rt.10.4.a"; } @@ -367,21 +354,6 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } -void Darwin::getMacosxVersionMin(const ArgList &Args, - unsigned (&Res)[3]) const { - if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) { - bool HadExtra; - if (!Driver::GetReleaseVersion(A->getValue(Args), Res[0], Res[1], Res[2], - HadExtra) || - HadExtra) { - const Driver &D = getDriver(); - D.Diag(clang::diag::err_drv_invalid_version_number) - << A->getAsString(Args); - } - } else - return getMacosxVersion(Res); -} - DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, const char *BoundArch) const { DerivedArgList *DAL = new DerivedArgList(Args, false); @@ -394,34 +366,84 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, // have something that works, we should reevaluate each translation // and try to push it down into tool specific logic. - Arg *OSXVersion = - Args.getLastArgNoClaim(options::OPT_mmacosx_version_min_EQ); - Arg *iPhoneVersion = - Args.getLastArgNoClaim(options::OPT_miphoneos_version_min_EQ); + Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); + Arg *iPhoneVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); if (OSXVersion && iPhoneVersion) { getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) << iPhoneVersion->getAsString(Args); + iPhoneVersion = 0; } else if (!OSXVersion && !iPhoneVersion) { - // Chose the default version based on the arch. + // If neither OS X nor iPhoneOS targets were specified, check for + // environment defines. + const char *OSXTarget = ::getenv("MACOSX_DEPLOYMENT_TARGET"); + const char *iPhoneOSTarget = ::getenv("IPHONEOS_DEPLOYMENT_TARGET"); + + // Ignore empty strings. + if (OSXTarget && OSXTarget[0] == '\0') + OSXTarget = 0; + if (iPhoneOSTarget && iPhoneOSTarget[0] == '\0') + iPhoneOSTarget = 0; + + // Diagnose conflicting deployment targets, and choose default platform + // based on the tool chain. // - // FIXME: Are there iPhone overrides for this? - - if (!isIPhoneOS()) { - // Look for MACOSX_DEPLOYMENT_TARGET, otherwise use the version - // from the host. - const char *Version = ::getenv("MACOSX_DEPLOYMENT_TARGET"); - if (!Version) - Version = MacosxVersionMin.c_str(); + // FIXME: Don't hardcode default here. + if (OSXTarget && iPhoneOSTarget) { + // FIXME: We should see if we can get away with warning or erroring on + // this. Perhaps put under -pedantic? + if (getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::thumb) + OSXVersion = 0; + else + iPhoneVersion = 0; + } + + if (OSXTarget) { const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - DAL->append(DAL->MakeJoinedArg(0, O, Version)); - } else { - const char *Version = IPhoneOSVersionMin.c_str(); + OSXVersion = DAL->MakeJoinedArg(0, O, OSXTarget); + DAL->append(OSXVersion); + } else if (iPhoneOSTarget) { const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); - DAL->append(DAL->MakeJoinedArg(0, O, Version)); + iPhoneVersion = DAL->MakeJoinedArg(0, O, iPhoneOSTarget); + DAL->append(iPhoneVersion); + } else { + // Otherwise, choose a default platform based on the tool chain. + // + // FIXME: Don't hardcode default here. + if (getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::thumb) { + const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); + iPhoneVersion = DAL->MakeJoinedArg(0, O, "3.0"); + DAL->append(iPhoneVersion); + } else { + const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); + OSXVersion = DAL->MakeJoinedArg(0, O, MacosxVersionMin); + DAL->append(OSXVersion); + } } } + // Set the tool chain target information. + unsigned Major, Minor, Micro; + bool HadExtra; + if (OSXVersion) { + assert(!iPhoneVersion && "Unknown target platform!"); + if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor, + Micro, HadExtra) || HadExtra || + Major != 10 || Minor >= 10 || Micro >= 10) + getDriver().Diag(clang::diag::err_drv_invalid_version_number) + << OSXVersion->getAsString(Args); + } else { + assert(iPhoneVersion && "Unknown target platform!"); + if (!Driver::GetReleaseVersion(iPhoneVersion->getValue(Args), Major, Minor, + Micro, HadExtra) || HadExtra || + Major >= 10 || Minor >= 100 || Micro >= 100) + getDriver().Diag(clang::diag::err_drv_invalid_version_number) + << iPhoneVersion->getAsString(Args); + } + setTarget(iPhoneVersion, Major, Minor, Micro); + for (ArgList::iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; @@ -618,6 +640,12 @@ bool Darwin::UseDwarfDebugFlags() const { return false; } +bool Darwin::UseSjLjExceptions() const { + // Darwin uses SjLj exceptions on ARM. + return (getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::thumb); +} + const char *Darwin::GetDefaultRelocationModel() const { return "pic"; } diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 3ca6ad88972c..fda08758c9bc 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -47,42 +47,60 @@ public: class VISIBILITY_HIDDEN Darwin : public ToolChain { mutable llvm::DenseMap<unsigned, Tool*> Tools; - /// Darwin version of tool chain. - unsigned DarwinVersion[3]; - - /// Whether this is this an iPhoneOS toolchain. + /// Whether the information on the target has been initialized. // - // FIXME: This should go away, such differences should be completely - // determined by the target triple. - bool IsIPhoneOS; + // FIXME: This should be eliminated. What we want to do is make this part of + // the "default target for arguments" selection process, once we get out of + // the argument translation business. + mutable bool TargetInitialized; + + /// Whether we are targetting iPhoneOS target. + mutable bool TargetIsIPhoneOS; + + /// The OS version we are targetting. + mutable unsigned TargetVersion[3]; /// The default macosx-version-min of this tool chain; empty until /// initialized. - mutable std::string MacosxVersionMin; - - /// The default iphoneos-version-min of this tool chain. - std::string IPhoneOSVersionMin; - - const char *getMacosxVersionMin() const; + std::string MacosxVersionMin; public: Darwin(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3], bool IsIPhoneOS); + const unsigned (&DarwinVersion)[3]); ~Darwin(); /// @name Darwin Specific Toolchain API /// { - void getDarwinVersion(unsigned (&Res)[3]) const { - Res[0] = DarwinVersion[0]; - Res[1] = DarwinVersion[1]; - Res[2] = DarwinVersion[2]; + // FIXME: Eliminate these ...Target functions and derive separate tool chains + // for these targets and put version in constructor. + void setTarget(bool isIPhoneOS, unsigned Major, unsigned Minor, + unsigned Micro) const { + // FIXME: For now, allow reinitialization as long as values don't + // change. This will go away when we move away from argument translation. + if (TargetInitialized && TargetIsIPhoneOS == isIPhoneOS && + TargetVersion[0] == Major && TargetVersion[1] == Minor && + TargetVersion[2] == Micro) + return; + + assert(!TargetInitialized && "Target already initialized!"); + TargetInitialized = true; + TargetIsIPhoneOS = isIPhoneOS; + TargetVersion[0] = Major; + TargetVersion[1] = Minor; + TargetVersion[2] = Micro; } - void getMacosxVersion(unsigned (&Res)[3]) const { - Res[0] = 10; - Res[1] = DarwinVersion[0] - 4; - Res[2] = DarwinVersion[1]; + bool isTargetIPhoneOS() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetIsIPhoneOS; + } + + void getTargetVersion(unsigned (&Res)[3]) const { + assert(TargetInitialized && "Target not initialized!"); + Res[0] = TargetVersion[0]; + Res[1] = TargetVersion[1]; + Res[2] = TargetVersion[2]; } /// getDarwinArchName - Get the "Darwin" arch name for a particular compiler @@ -90,11 +108,7 @@ public: /// distinct architectures. llvm::StringRef getDarwinArchName(const ArgList &Args) const; - /// getMacosxVersionMin - Get the effective -mmacosx-version-min, which is - /// either the -mmacosx-version-min, or the current version if unspecified. - void getMacosxVersionMin(const ArgList &Args, unsigned (&Res)[3]) const; - - static bool isMacosxVersionLT(unsigned (&A)[3], unsigned (&B)[3]) { + static bool isVersionLT(unsigned (&A)[3], unsigned (&B)[3]) { for (unsigned i=0; i < 3; ++i) { if (A[i] > B[i]) return false; if (A[i] < B[i]) return true; @@ -102,18 +116,16 @@ public: return false; } - static bool isMacosxVersionLT(unsigned (&A)[3], - unsigned V0, unsigned V1=0, unsigned V2=0) { + bool isIPhoneOSVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const { + assert(isTargetIPhoneOS() && "Unexpected call for OS X target!"); unsigned B[3] = { V0, V1, V2 }; - return isMacosxVersionLT(A, B); + return isVersionLT(TargetVersion, B); } - const char *getMacosxVersionStr() const { - return MacosxVersionMin.c_str(); - } - - const char *getIPhoneOSVersionStr() const { - return IPhoneOSVersionMin.c_str(); + bool isMacosxVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const { + assert(!isTargetIPhoneOS() && "Unexpected call for iPhoneOS target!"); + unsigned B[3] = { V0, V1, V2 }; + return isVersionLT(TargetVersion, B); } /// AddLinkSearchPathArgs - Add the linker search paths to \arg CmdArgs. @@ -129,8 +141,6 @@ public: virtual void AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const = 0; - bool isIPhoneOS() const { return IsIPhoneOS; } - /// } /// @name ToolChain Implementation /// { @@ -141,24 +151,33 @@ public: virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; virtual bool IsBlocksDefault() const { - // Blocks default to on for 10.6 (darwin10) and beyond. - return (DarwinVersion[0] > 9); + // Blocks default to on for OS X 10.6 and iPhoneOS 3.0 and beyond. + if (isTargetIPhoneOS()) + return !isIPhoneOSVersionLT(3); + else + return !isMacosxVersionLT(10, 6); } virtual bool IsObjCNonFragileABIDefault() const { - // Non-fragile ABI default to on for 10.5 (darwin9) and beyond on x86-64. - return (DarwinVersion[0] >= 9 && - getTriple().getArch() == llvm::Triple::x86_64); + // Non-fragile ABI default to on for iPhoneOS and x86-64. + return isTargetIPhoneOS() || getTriple().getArch() == llvm::Triple::x86_64; + } + virtual bool IsObjCLegacyDispatchDefault() const { + // This is only used with the non-fragile ABI. + return (getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::thumb); } virtual bool IsUnwindTablesDefault() const; virtual unsigned GetDefaultStackProtectorLevel() const { - // Stack protectors default to on for 10.6 (darwin10) and beyond. - return (DarwinVersion[0] > 9) ? 1 : 0; + // Stack protectors default to on for 10.6 and beyond. + return !isTargetIPhoneOS() && !isMacosxVersionLT(10, 6); } virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; virtual bool UseDwarfDebugFlags() const; + virtual bool UseSjLjExceptions() const; + /// } }; @@ -166,7 +185,7 @@ public: class VISIBILITY_HIDDEN DarwinClang : public Darwin { public: DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3], bool IsIPhoneOS); + const unsigned (&DarwinVersion)[3]); /// @name Darwin ToolChain Implementation /// { @@ -190,8 +209,8 @@ class VISIBILITY_HIDDEN DarwinGCC : public Darwin { public: DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3], const unsigned (&GCCVersion)[3], - bool IsIPhoneOS); + const unsigned (&DarwinVersion)[3], + const unsigned (&GCCVersion)[3]); /// @name Darwin ToolChain Implementation /// { diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index afb22a236767..aff70bc7ba0d 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -512,7 +512,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, // Select the default CPU if none was given (or detection failed). if (!CPUName) { // FIXME: Need target hooks. - if (memcmp(getToolChain().getOS().c_str(), "darwin", 6) == 0) { + if (getToolChain().getOS().startswith("darwin")) { if (getToolChain().getArchName() == "x86_64") CPUName = "core2"; else if (getToolChain().getArchName() == "i386") @@ -586,43 +586,35 @@ static std::string getEffectiveClangTriple(const Driver &D, const ArgList &Args) { llvm::Triple Triple(getLLVMTriple(TC, Args)); + // Handle -mmacosx-version-min and -miphoneos-version-min. if (Triple.getOS() != llvm::Triple::Darwin) { // Diagnose use of -mmacosx-version-min and -miphoneos-version-min on // non-Darwin. if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ, options::OPT_miphoneos_version_min_EQ)) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); - return Triple.getTriple(); - } - - // If -mmacosx-version-min=10.3.9 is specified, change the effective triple - // from being something like powerpc-apple-darwin9 to powerpc-apple-darwin7. - if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) { - unsigned Major, Minor, Micro; - bool HadExtra; - if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro, - HadExtra) || HadExtra || - Major != 10) - D.Diag(clang::diag::err_drv_invalid_version_number) - << A->getAsString(Args); + } else { + const toolchains::Darwin &DarwinTC( + reinterpret_cast<const toolchains::Darwin&>(TC)); + unsigned Version[3]; + DarwinTC.getTargetVersion(Version); + + // Mangle the target version into the OS triple component. For historical + // reasons that make little sense, the version passed here is the "darwin" + // version, which drops the 10 and offsets by 4. See inverse code when + // setting the OS version preprocessor define. + if (!DarwinTC.isTargetIPhoneOS()) { + Version[0] = Version[1] + 4; + Version[1] = Version[2]; + Version[2] = 0; + } else { + // Use the environment to communicate that we are targetting iPhoneOS. + Triple.setEnvironmentName("iphoneos"); + } - // Mangle the MacOS version min number into the Darwin number: e.g. 10.3.9 - // is darwin7.9. - llvm::SmallString<16> Str; - llvm::raw_svector_ostream(Str) << "darwin" << Minor + 4 << "." << Micro; - Triple.setOSName(Str.str()); - } else if (Arg *A = Args.getLastArg(options::OPT_miphoneos_version_min_EQ)) { - unsigned Major, Minor, Micro; - bool HadExtra; - if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro, - HadExtra) || HadExtra) - D.Diag(clang::diag::err_drv_invalid_version_number) - << A->getAsString(Args); - - // Mangle the iPhoneOS version number into the Darwin number: e.g. 2.0 is 2 - // -> 9.2.0. llvm::SmallString<16> Str; - llvm::raw_svector_ostream(Str) << "darwin9." << Major << "." << Minor; + llvm::raw_svector_ostream(Str) << "darwin" << Version[0] + << "." << Version[1] << "." << Version[2]; Triple.setOSName(Str.str()); } @@ -659,6 +651,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-Eonly"); else CmdArgs.push_back("-E"); + } else if (isa<AssembleJobAction>(JA)) { + CmdArgs.push_back("-emit-obj"); } else if (isa<PrecompileJobAction>(JA)) { // Use PCH if the user requested it, except for C++ (for now). bool UsePCH = D.CCCUsePCH; @@ -682,12 +676,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-S"); } else if (JA.getType() == types::TY_AST) { CmdArgs.push_back("-emit-pch"); + } else if (JA.getType() == types::TY_RewrittenObjC) { + CmdArgs.push_back("-rewrite-objc"); + } else { + assert(JA.getType() == types::TY_PP_Asm && + "Unexpected output type!"); } } // The make clang go fast button. CmdArgs.push_back("-disable-free"); + // Disable the verification pass in -asserts builds. +#ifdef NDEBUG + CmdArgs.push_back("-disable-llvm-verifier"); +#endif + // Set the main file name, so that debug info works even with // -save-temps. CmdArgs.push_back("-main-file-name"); @@ -707,14 +711,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { - CmdArgs.push_back("-warn-dead-stores"); - CmdArgs.push_back("-warn-security-syntactic"); - CmdArgs.push_back("-checker-cfref"); + CmdArgs.push_back("-analyzer-check-dead-stores"); + CmdArgs.push_back("-analyzer-check-security-syntactic"); + CmdArgs.push_back("-analyzer-check-objc-mem"); CmdArgs.push_back("-analyzer-eagerly-assume"); - CmdArgs.push_back("-warn-objc-methodsigs"); + CmdArgs.push_back("-analyzer-check-objc-methodsigs"); // Do not enable the missing -dealloc check. - // '-warn-objc-missing-dealloc', - CmdArgs.push_back("-warn-objc-unused-ivars"); + // '-analyzer-check-objc-missing-dealloc', + CmdArgs.push_back("-analyzer-check-objc-unused-ivars"); } // Set the output format. The default is plist, for (lame) historical @@ -909,8 +913,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } else { // Honor -std-default. - Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, - "-std=", /*Joined=*/true); + // + // FIXME: Clang doesn't correctly handle -std= when the input language + // doesn't match. For the time being just ignore this for C++ inputs; + // eventually we want to do all the standard defaulting here instead of + // splitting it between the driver and clang -cc1. + if (!types::isCXX(InputType)) + Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, + "-std=", /*Joined=*/true); Args.AddLastArg(CmdArgs, options::OPT_trigraphs); } @@ -1004,6 +1014,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (needsExceptions(Args, InputType, getToolChain().getTriple())) CmdArgs.push_back("-fexceptions"); + if (getToolChain().UseSjLjExceptions()) + CmdArgs.push_back("-fsjlj-exceptions"); + // -frtti is default. if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti)) CmdArgs.push_back("-fno-rtti"); @@ -1013,6 +1026,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, isSignedCharDefault(getToolChain().getTriple()))) CmdArgs.push_back("-fno-signed-char"); + // -fthreadsafe-static is default. + if (!Args.hasFlag(options::OPT_fthreadsafe_statics, + options::OPT_fno_threadsafe_statics)) + CmdArgs.push_back("-fno-threadsafe-statics"); + // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) @@ -1026,10 +1044,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fobjc-nonfragile-abi=0 is default. if (types::isObjC(InputType)) { if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) || - getToolChain().IsObjCNonFragileABIDefault()) + getToolChain().IsObjCNonFragileABIDefault()) { CmdArgs.push_back("-fobjc-nonfragile-abi"); + + // -fobjc-legacy-dispatch is only relevant with the nonfragile-abi, and + // defaults to off. + if (Args.hasFlag(options::OPT_fobjc_legacy_dispatch, + options::OPT_fno_objc_legacy_dispatch, + getToolChain().IsObjCLegacyDispatchDefault())) + CmdArgs.push_back("-fobjc-legacy-dispatch"); + } } + if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, + options::OPT_fno_assume_sane_operator_new)) + CmdArgs.push_back("-fno-assume-sane-operator-new"); + // -fshort-wchar default varies depending on platform; only // pass if specified. if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) { @@ -1066,6 +1096,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_diagnostics_fixit_info)) CmdArgs.push_back("-fno-diagnostics-fixit-info"); + Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_binary); + // Enable -fdiagnostics-show-option by default. if (Args.hasFlag(options::OPT_fdiagnostics_show_option, options::OPT_fno_diagnostics_show_option)) @@ -1213,7 +1245,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, } } - RenderExtraToolArgs(CmdArgs); + RenderExtraToolArgs(JA, CmdArgs); // If using a driver driver, force the arch. const std::string &Arch = getToolChain().getArchName(); @@ -1291,23 +1323,39 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } -void gcc::Preprocess::RenderExtraToolArgs(ArgStringList &CmdArgs) const { +void gcc::Preprocess::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { CmdArgs.push_back("-E"); } -void gcc::Precompile::RenderExtraToolArgs(ArgStringList &CmdArgs) const { +void gcc::Precompile::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { // The type is good enough. } -void gcc::Compile::RenderExtraToolArgs(ArgStringList &CmdArgs) const { - CmdArgs.push_back("-S"); +void gcc::Compile::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + + // If -flto, etc. are present then make sure not to force assembly output. + if (JA.getType() == types::TY_LLVMBC) + CmdArgs.push_back("-c"); + else { + if (JA.getType() != types::TY_PP_Asm) + D.Diag(clang::diag::err_drv_invalid_gcc_output_type) + << getTypeName(JA.getType()); + + CmdArgs.push_back("-S"); + } } -void gcc::Assemble::RenderExtraToolArgs(ArgStringList &CmdArgs) const { +void gcc::Assemble::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { CmdArgs.push_back("-c"); } -void gcc::Link::RenderExtraToolArgs(ArgStringList &CmdArgs) const { +void gcc::Link::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { // The types are (hopefully) good enough. } @@ -1703,6 +1751,10 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, else if (Output.getType() == types::TY_AST) D.Diag(clang::diag::err_drv_no_ast_support) << getToolChain().getTripleString(); + else if (JA.getType() != types::TY_PP_Asm && + JA.getType() != types::TY_PCH) + D.Diag(clang::diag::err_drv_invalid_gcc_output_type) + << getTypeName(JA.getType()); ArgStringList OutputArgs; if (Output.getType() != types::TY_PCH) { @@ -1798,7 +1850,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, // Derived from asm spec. AddDarwinArch(Args, CmdArgs); - if (!getDarwinToolChain().isIPhoneOS() || + if (!getDarwinToolChain().isTargetIPhoneOS() || Args.hasArg(options::OPT_force__cpusubtype__ALL)) CmdArgs.push_back("-force_cpusubtype_ALL"); @@ -1921,7 +1973,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, Args.AddLastArg(CmdArgs, options::OPT_all__load); Args.AddAllArgs(CmdArgs, options::OPT_allowable__client); Args.AddLastArg(CmdArgs, options::OPT_bind__at__load); - if (getDarwinToolChain().isIPhoneOS()) + if (getDarwinToolChain().isTargetIPhoneOS()) Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal); Args.AddLastArg(CmdArgs, options::OPT_dead__strip); Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms); @@ -1933,20 +1985,11 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_image__base); Args.AddAllArgs(CmdArgs, options::OPT_init); - if (!Args.hasArg(options::OPT_mmacosx_version_min_EQ) && - !Args.hasArg(options::OPT_miphoneos_version_min_EQ)) { - // Add default version min. - if (!getDarwinToolChain().isIPhoneOS()) { - CmdArgs.push_back("-macosx_version_min"); - CmdArgs.push_back(getDarwinToolChain().getMacosxVersionStr()); - } else { - CmdArgs.push_back("-iphoneos_version_min"); - CmdArgs.push_back(getDarwinToolChain().getIPhoneOSVersionStr()); - } - } - - // Adding all arguments doesn't make sense here but this is what - // gcc does. + // Adding all arguments doesn't make sense here but this is what gcc does. One + // of this should always be present thanks to argument translation. + assert((Args.hasArg(options::OPT_mmacosx_version_min_EQ) || + Args.hasArg(options::OPT_miphoneos_version_min_EQ)) && + "Missing version argument (lost in translation)?"); Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ, "-macosx_version_min"); Args.AddAllArgsTranslated(CmdArgs, options::OPT_miphoneos_version_min_EQ, @@ -1978,7 +2021,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella); Args.AddAllArgsTranslated(CmdArgs, options::OPT_isysroot, "-syslibroot"); - if (getDarwinToolChain().isIPhoneOS()) { + if (getDarwinToolChain().isTargetIPhoneOS()) { if (!Args.hasArg(options::OPT_isysroot)) { CmdArgs.push_back("-syslibroot"); CmdArgs.push_back("/Developer/SDKs/Extra"); @@ -2037,26 +2080,32 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - - unsigned MacosxVersionMin[3]; - getDarwinToolChain().getMacosxVersionMin(Args, MacosxVersionMin); - if (!Args.hasArg(options::OPT_A) && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { // Derived from startfile spec. if (Args.hasArg(options::OPT_dynamiclib)) { // Derived from darwin_dylib1 spec. - if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5)) - CmdArgs.push_back("-ldylib1.o"); - else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 6)) - CmdArgs.push_back("-ldylib1.10.5.o"); + if (getDarwinToolChain().isTargetIPhoneOS()) { + if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-ldylib1.o"); + } else { + if (getDarwinToolChain().isMacosxVersionLT(10, 5)) + CmdArgs.push_back("-ldylib1.o"); + else if (getDarwinToolChain().isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-ldylib1.10.5.o"); + } } else { if (Args.hasArg(options::OPT_bundle)) { if (!Args.hasArg(options::OPT_static)) { // Derived from darwin_bundle1 spec. - if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 6)) - CmdArgs.push_back("-lbundle1.o"); + if (getDarwinToolChain().isTargetIPhoneOS()) { + if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-lbundle1.o"); + } else { + if (getDarwinToolChain().isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-lbundle1.o"); + } } } else { if (Args.hasArg(options::OPT_pg)) { @@ -2076,26 +2125,29 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lcrt0.o"); } else { // Derived from darwin_crt1 spec. - if (getDarwinToolChain().isIPhoneOS()) { - CmdArgs.push_back("-lcrt1.o"); - } else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, - 10, 5)) - CmdArgs.push_back("-lcrt1.o"); - else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, - 10, 6)) - CmdArgs.push_back("-lcrt1.10.5.o"); - else - CmdArgs.push_back("-lcrt1.10.6.o"); - - // darwin_crt2 spec is empty. + if (getDarwinToolChain().isTargetIPhoneOS()) { + if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-lcrt1.o"); + else + CmdArgs.push_back("-lcrt1.3.1.o"); + } else { + if (getDarwinToolChain().isMacosxVersionLT(10, 5)) + CmdArgs.push_back("-lcrt1.o"); + else if (getDarwinToolChain().isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-lcrt1.10.5.o"); + else + CmdArgs.push_back("-lcrt1.10.6.o"); + + // darwin_crt2 spec is empty. + } } } } } - if (Args.hasArg(options::OPT_shared_libgcc) && - !Args.hasArg(options::OPT_miphoneos_version_min_EQ) && - getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5)) { + if (!getDarwinToolChain().isTargetIPhoneOS() && + Args.hasArg(options::OPT_shared_libgcc) && + getDarwinToolChain().isMacosxVersionLT(10, 5)) { const char *Str = Args.MakeArgString(getToolChain().GetFilePath(C, "crt3.o")); CmdArgs.push_back(Str); diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index abd8cfc6d42f..db596417a9d2 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -41,6 +41,7 @@ namespace tools { virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } + virtual bool hasIntegratedAssembler() const { return true; } virtual bool hasIntegratedCPP() const { return true; } virtual void ConstructJob(Compilation &C, const JobAction &JA, @@ -66,7 +67,8 @@ namespace gcc { /// RenderExtraToolArgs - Render any arguments necessary to force /// the particular tool mode. - virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const = 0; + virtual void RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const = 0; }; @@ -78,7 +80,8 @@ namespace gcc { virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } - virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const; + virtual void RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const; }; class VISIBILITY_HIDDEN Precompile : public Common { @@ -89,7 +92,8 @@ namespace gcc { virtual bool canPipeOutput() const { return false; } virtual bool hasIntegratedCPP() const { return true; } - virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const; + virtual void RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const; }; class VISIBILITY_HIDDEN Compile : public Common { @@ -100,7 +104,8 @@ namespace gcc { virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return true; } - virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const; + virtual void RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const; }; class VISIBILITY_HIDDEN Assemble : public Common { @@ -111,7 +116,8 @@ namespace gcc { virtual bool canPipeOutput() const { return false; } virtual bool hasIntegratedCPP() const { return false; } - virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const; + virtual void RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const; }; class VISIBILITY_HIDDEN Link : public Common { @@ -122,7 +128,8 @@ namespace gcc { virtual bool canPipeOutput() const { return false; } virtual bool hasIntegratedCPP() const { return false; } - virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const; + virtual void RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const; }; } // end namespace gcc diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 33cb94e02dc3..ebbd720ceb63 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -564,7 +564,7 @@ public: if (RD->isInvalidDecl()) continue; - if (!RD->getDefinition(C)) + if (!RD->getDefinition()) continue; // FIXME: Do we really need to hard code this? diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp new file mode 100644 index 000000000000..2228ea45df33 --- /dev/null +++ b/lib/Frontend/ASTMerge.cpp @@ -0,0 +1,103 @@ +//===-- ASTMerge.cpp - AST Merging Frontent Action --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/ASTImporter.h" + +using namespace clang; + +ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return AdaptedAction->CreateASTConsumer(CI, InFile); +} + +bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI, + llvm::StringRef Filename) { + // FIXME: This is a hack. We need a better way to communicate the + // AST file, compiler instance, and file name than member variables + // of FrontendAction. + AdaptedAction->setCurrentFile(getCurrentFile(), takeCurrentASTUnit()); + AdaptedAction->setCompilerInstance(&CI); + return AdaptedAction->BeginSourceFileAction(CI, Filename); +} + +void ASTMergeAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + CI.getDiagnostics().getClient()->BeginSourceFile( + CI.getASTContext().getLangOptions()); + CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument, + &CI.getASTContext()); + for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { + ASTUnit *Unit = ASTUnit::LoadFromPCHFile(ASTFiles[I], CI.getDiagnostics(), + false); + if (!Unit) + continue; + + ASTImporter Importer(CI.getDiagnostics(), + CI.getASTContext(), + CI.getFileManager(), + Unit->getASTContext(), + Unit->getFileManager()); + + TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); + for (DeclContext::decl_iterator D = TU->decls_begin(), + DEnd = TU->decls_end(); + D != DEnd; ++D) { + // Don't re-import __va_list_tag, __builtin_va_list. + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) + if (IdentifierInfo *II = ND->getIdentifier()) + if (II->isStr("__va_list_tag") || II->isStr("__builtin_va_list")) + continue; + + Importer.Import(*D); + } + + delete Unit; + } + + AdaptedAction->ExecuteAction(); + CI.getDiagnostics().getClient()->EndSourceFile(); +} + +void ASTMergeAction::EndSourceFileAction() { + return AdaptedAction->EndSourceFileAction(); +} + +ASTMergeAction::ASTMergeAction(FrontendAction *AdaptedAction, + std::string *ASTFiles, unsigned NumASTFiles) + : AdaptedAction(AdaptedAction), ASTFiles(ASTFiles, ASTFiles + NumASTFiles) { + assert(AdaptedAction && "ASTMergeAction needs an action to adapt"); +} + +ASTMergeAction::~ASTMergeAction() { + delete AdaptedAction; +} + +bool ASTMergeAction::usesPreprocessorOnly() const { + return AdaptedAction->usesPreprocessorOnly(); +} + +bool ASTMergeAction::usesCompleteTranslationUnit() { + return AdaptedAction->usesCompleteTranslationUnit(); +} + +bool ASTMergeAction::hasPCHSupport() const { + return AdaptedAction->hasPCHSupport(); +} + +bool ASTMergeAction::hasASTSupport() const { + return AdaptedAction->hasASTSupport(); +} + +bool ASTMergeAction::hasCodeCompletionSupport() const { + return AdaptedAction->hasCodeCompletionSupport(); +} diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 2fb47cbd8a85..a0c4889c1631 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -98,13 +98,12 @@ const std::string &ASTUnit::getOriginalSourceFileName() { const std::string &ASTUnit::getPCHFileName() { assert(isMainFileAST() && "Not an ASTUnit from a PCH file!"); - return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName(); + return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName(); } ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, Diagnostic &Diags, bool OnlyLocalDecls, - bool UseBumpAllocator, RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); @@ -184,7 +183,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, PP.getIdentifierTable(), PP.getSelectorTable(), PP.getBuiltinInfo(), - /* FreeMemory = */ !UseBumpAllocator, + /* FreeMemory = */ false, /* size_reserve = */0)); ASTContext &Context = *AST->Ctx.get(); @@ -230,7 +229,7 @@ public: } -ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, +ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, Diagnostic &Diags, bool OnlyLocalDecls) { // Create the compiler instance to use for building the AST. @@ -238,7 +237,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, llvm::OwningPtr<ASTUnit> AST; llvm::OwningPtr<TopLevelDeclTrackerAction> Act; - Clang.getInvocation() = CI; + Clang.setInvocation(CI); Clang.setDiagnostics(&Diags); Clang.setDiagnosticClient(Diags.getClient()); @@ -294,7 +293,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, Clang.takeDiagnosticClient(); Clang.takeDiagnostics(); + Clang.takeInvocation(); + AST->Invocation.reset(Clang.takeInvocation()); return AST.take(); error: @@ -310,7 +311,6 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, Diagnostic &Diags, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls, - bool UseBumpAllocator, RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { llvm::SmallVector<const char *, 16> Args; @@ -324,6 +324,10 @@ 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); + + // Don't check that inputs exist, they have been remapped. + TheDriver.setCheckInputsExist(false); + llvm::OwningPtr<driver::Compilation> C( TheDriver.BuildCompilation(Args.size(), Args.data())); @@ -345,19 +349,19 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, } const driver::ArgStringList &CCArgs = Cmd->getArguments(); - CompilerInvocation CI; - CompilerInvocation::CreateFromArgs(CI, (const char**) CCArgs.data(), + llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation); + CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(), (const char**) CCArgs.data()+CCArgs.size(), Diags); // Override any files that need remapping for (unsigned I = 0; I != NumRemappedFiles; ++I) - CI.getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, - RemappedFiles[I].second); + CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + RemappedFiles[I].second); // Override the resources path. - CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath; + CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; - CI.getFrontendOpts().DisableFree = UseBumpAllocator; - return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls); + CI->getFrontendOpts().DisableFree = true; + return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls); } diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 45a3b15caecc..d764fd078968 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -18,14 +18,15 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" #include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/Analyses/UninitializedValues.h" #include "clang/Analysis/CFG.h" -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/ManagerRegistry.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/PathSensitive/AnalysisManager.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Checker/Checkers/LocalCheckers.h" +#include "clang/Checker/ManagerRegistry.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/PathSensitive/AnalysisManager.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/PathSensitive/GRTransferFuncs.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/PathDiagnosticClients.h" @@ -64,13 +65,17 @@ namespace { class AnalysisConsumer : public ASTConsumer { public: typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); - + typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M, + TranslationUnitDecl &TU); + private: typedef std::vector<CodeAction> Actions; + typedef std::vector<TUAction> TUActions; + Actions FunctionActions; Actions ObjCMethodActions; Actions ObjCImplementationActions; - Actions TranslationUnitActions; + TUActions TranslationUnitActions; public: ASTContext* Ctx; @@ -133,11 +138,11 @@ public: } } } - + void DisplayFunction(const Decl *D) { if (!Opts.AnalyzerDisplayProgress || declDisplayed) return; - + declDisplayed = true; SourceManager &SM = Mgr->getASTContext().getSourceManager(); PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); @@ -162,7 +167,7 @@ public: ObjCImplementationActions.push_back(action); } - void addTranslationUnitAction(CodeAction action) { + void addTranslationUnitAction(TUAction action) { TranslationUnitActions.push_back(action); } @@ -191,7 +196,7 @@ public: namespace llvm { template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> { - static inline void Profile(AnalysisConsumer::CodeAction X, + static inline void Profile(AnalysisConsumer::CodeAction X, FoldingSetNodeID& ID) { ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X))); } @@ -204,42 +209,30 @@ namespace llvm { void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { switch (D->getKind()) { + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::CXXMethod: case Decl::Function: { FunctionDecl* FD = cast<FunctionDecl>(D); - if (!Opts.AnalyzeSpecificFunction.empty() && - Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName()) - break; + FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) + break; - Stmt* Body = FD->getBody(); - if (Body) HandleCode(FD, Body, FunctionActions); + if (Stmt *Body = FD->getBody()) + HandleCode(FD, Body, FunctionActions); break; } case Decl::ObjCMethod: { ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D); - if (Opts.AnalyzeSpecificFunction.size() > 0 && + if (!Opts.AnalyzeSpecificFunction.empty() && Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString()) return; - Stmt* Body = MD->getBody(); - if (Body) HandleCode(MD, Body, ObjCMethodActions); - break; - } - - case Decl::CXXConstructor: - case Decl::CXXDestructor: - case Decl::CXXConversion: - case Decl::CXXMethod: { - CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D); - - if (Opts.AnalyzeSpecificFunction.size() > 0 && - Opts.AnalyzeSpecificFunction != CXXMD->getName()) - return; - - Stmt *Body = CXXMD->getBody(); - if (Body) HandleCode(CXXMD, Body, FunctionActions); + if (Stmt* Body = MD->getBody()) + HandleCode(MD, Body, ObjCMethodActions); break; } @@ -249,30 +242,12 @@ void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { } void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { - + TranslationUnitDecl *TU = C.getTranslationUnitDecl(); - - if (!TranslationUnitActions.empty()) { - // Find the entry function definition (if any). - FunctionDecl *FD = 0; - // Must specify an entry function. - if (!Opts.AnalyzeSpecificFunction.empty()) { - for (DeclContext::decl_iterator I=TU->decls_begin(), E=TU->decls_end(); - I != E; ++I) { - if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I)) - if (fd->isThisDeclarationADefinition() && - fd->getNameAsString() == Opts.AnalyzeSpecificFunction) { - FD = fd; - break; - } - } - } - if (FD) { - for (Actions::iterator I = TranslationUnitActions.begin(), - E = TranslationUnitActions.end(); I != E; ++I) - (*I)(*this, *Mgr, FD); - } + for (TUActions::iterator I = TranslationUnitActions.begin(), + E = TranslationUnitActions.end(); I != E; ++I) { + (*I)(*this, *Mgr, *TU); } if (!ObjCImplementationActions.empty()) { @@ -293,7 +268,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) WL.push_back(BD); - + for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); I!=E; ++I) if (DeclContext *DC = dyn_cast<DeclContext>(*I)) @@ -314,14 +289,14 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { // Clear the AnalysisManager of old AnalysisContexts. Mgr->ClearContexts(); - + // Dispatch on the actions. llvm::SmallVector<Decl*, 10> WL; WL.push_back(D); - + if (Body && Opts.AnalyzeNestedBlocks) FindBlocks(cast<DeclContext>(D), WL); - + for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); WI != WE; ++WI) @@ -351,7 +326,7 @@ static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, - Decl *D, + Decl *D, GRTransferFuncs* tf) { llvm::OwningPtr<GRTransferFuncs> TF(tf); @@ -363,18 +338,18 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, // information to see if the CFG is valid. // FIXME: Inter-procedural analysis will need to handle invalid CFGs. if (!mgr.getLiveVariables(D)) - return; - + return; + GRExprEngine Eng(mgr, TF.take()); - + if (C.Opts.EnableExperimentalInternalChecks) RegisterExperimentalInternalChecks(Eng); - + RegisterAppleChecks(Eng, *D); - + if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); - + // Set the graph auditor. llvm::OwningPtr<ExplodedNode::Auditor> Auditor; if (mgr.shouldVisualizeUbigraph()) { @@ -397,7 +372,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Eng.getBugReporter().FlushReports(); } -static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr, +static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D, bool GCEnabled) { GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), @@ -407,23 +382,23 @@ static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr, ActionGRExprEngine(C, mgr, D, TF); } -static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr, +static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { switch (mgr.getLangOptions().getGCMode()) { default: assert (false && "Invalid GC mode."); case LangOptions::NonGC: - ActionCheckerCFRefAux(C, mgr, D, false); + ActionObjCMemCheckerAux(C, mgr, D, false); break; case LangOptions::GCOnly: - ActionCheckerCFRefAux(C, mgr, D, true); + ActionObjCMemCheckerAux(C, mgr, D, true); break; case LangOptions::HybridGC: - ActionCheckerCFRefAux(C, mgr, D, false); - ActionCheckerCFRefAux(C, mgr, D, true); + ActionObjCMemCheckerAux(C, mgr, D, false); + ActionObjCMemCheckerAux(C, mgr, D, true); break; } } @@ -457,6 +432,13 @@ static void ActionSecuritySyntacticChecks(AnalysisConsumer &C, CheckSecuritySyntaxOnly(D, BR); } +static void ActionLLVMConventionChecker(AnalysisConsumer &C, + AnalysisManager &mgr, + TranslationUnitDecl &TU) { + BugReporter BR(mgr); + CheckLLVMConventions(TU, BR); +} + static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly) @@ -489,8 +471,29 @@ static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, } static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, - Decl *D) { - // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup. + TranslationUnitDecl &TU) { + + // Find the entry function definition (if any). + FunctionDecl *D = 0; + + // Must specify an entry function. + if (!C.Opts.AnalyzeSpecificFunction.empty()) { + for (DeclContext::decl_iterator I=TU.decls_begin(), E=TU.decls_end(); + I != E; ++I) { + if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I)) + if (fd->isThisDeclarationADefinition() && + fd->getNameAsString() == C.Opts.AnalyzeSpecificFunction) { + D = fd; + break; + } + } + } + + if (!D) + return; + + + // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup. // Display progress. C.DisplayFunction(D); @@ -500,9 +503,9 @@ static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, if (C.Opts.EnableExperimentalInternalChecks) RegisterExperimentalInternalChecks(Eng); - + RegisterAppleChecks(Eng, *D); - + if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp index 9be6786b5f75..f5291a9525e7 100644 --- a/lib/Frontend/Backend.cpp +++ b/lib/Frontend/Backend.cpp @@ -17,7 +17,6 @@ #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Module.h" -#include "llvm/ModuleProvider.h" #include "llvm/PassManager.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Assembly/PrintModulePass.h" @@ -56,7 +55,6 @@ namespace { llvm::Module *TheModule; llvm::TargetData *TheTargetData; - mutable llvm::ModuleProvider *ModuleProvider; mutable FunctionPassManager *CodeGenPasses; mutable PassManager *PerModulePasses; mutable FunctionPassManager *PerFunctionPasses; @@ -89,7 +87,7 @@ namespace { LLVMIRGeneration("LLVM IR Generation Time"), CodeGenerationTime("Code Generation Time"), Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)), - TheModule(0), TheTargetData(0), ModuleProvider(0), + TheModule(0), TheTargetData(0), CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) { if (AsmOutStream) @@ -101,7 +99,7 @@ namespace { ~BackendConsumer() { delete TheTargetData; - delete ModuleProvider; + delete TheModule; delete CodeGenPasses; delete PerModulePasses; delete PerFunctionPasses; @@ -116,7 +114,6 @@ namespace { Gen->Initialize(Ctx); TheModule = Gen->GetModule(); - ModuleProvider = new ExistingModuleProvider(TheModule); TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); if (llvm::TimePassesIsEnabled) @@ -172,7 +169,7 @@ namespace { FunctionPassManager *BackendConsumer::getCodeGenPasses() const { if (!CodeGenPasses) { - CodeGenPasses = new FunctionPassManager(ModuleProvider); + CodeGenPasses = new FunctionPassManager(TheModule); CodeGenPasses->add(new TargetData(*TheTargetData)); } @@ -190,7 +187,7 @@ PassManager *BackendConsumer::getPerModulePasses() const { FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { if (!PerFunctionPasses) { - PerFunctionPasses = new FunctionPassManager(ModuleProvider); + PerFunctionPasses = new FunctionPassManager(TheModule); PerFunctionPasses->add(new TargetData(*TheTargetData)); } @@ -306,20 +303,12 @@ bool BackendConsumer::AddEmitPasses() { case 3: OptLevel = CodeGenOpt::Aggressive; break; } - // Normal mode, emit a .s file by running the code generator. - // Note, this also adds codegenerator level optimization passes. - switch (TM->addPassesToEmitFile(*PM, FormattedOutStream, - TargetMachine::AssemblyFile, OptLevel)) { - default: - case FileModel::Error: - Diags.Report(diag::err_fe_unable_to_interface_with_target); - return false; - case FileModel::AsmFile: - break; - } - - if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0, - OptLevel)) { + // Normal mode, emit a .s or .o file by running the code generator. Note, + // this also adds codegenerator level optimization passes. + TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile; + if (Action == Backend_EmitObj) + CGFT = TargetMachine::CGFT_ObjectFile; + if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel)) { Diags.Report(diag::err_fe_unable_to_interface_with_target); return false; } @@ -354,11 +343,11 @@ void BackendConsumer::CreatePasses() { // Set the inline threshold following llvm-gcc. // // FIXME: Derive these constants in a principled fashion. - unsigned Threshold = 200; + unsigned Threshold = 225; if (CodeGenOpts.OptimizeSize) - Threshold = 50; + Threshold = 75; else if (OptLevel > 2) - Threshold = 250; + Threshold = 275; InliningPass = createFunctionInliningPass(Threshold); break; } @@ -392,7 +381,6 @@ void BackendConsumer::EmitAssembly() { if (!M) { // The module has been released by IR gen on failures, do not // double free. - ModuleProvider->releaseModule(); TheModule = 0; return; } diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 58aaa43aab8f..1d0b5c12041a 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangFrontend ASTConsumers.cpp + ASTMerge.cpp ASTUnit.cpp AnalysisConsumer.cpp Backend.cpp diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 19c740d17a83..917cbd711ad3 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -35,15 +35,19 @@ #include "llvm/System/Program.h" using namespace clang; -CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext, - bool _OwnsLLVMContext) - : LLVMContext(_LLVMContext), - OwnsLLVMContext(_OwnsLLVMContext) { - } +CompilerInstance::CompilerInstance() + : Invocation(new CompilerInvocation()) { +} CompilerInstance::~CompilerInstance() { - if (OwnsLLVMContext) - delete LLVMContext; +} + +void CompilerInstance::setLLVMContext(llvm::LLVMContext *Value) { + LLVMContext.reset(Value); +} + +void CompilerInstance::setInvocation(CompilerInvocation *Value) { + Invocation.reset(Value); } void CompilerInstance::setDiagnostics(Diagnostic *Value) { @@ -83,6 +87,23 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { } // Diagnostics +namespace { + class BinaryDiagnosticSerializer : public DiagnosticClient { + llvm::raw_ostream &OS; + SourceManager *SourceMgr; + public: + explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS) + : OS(OS), SourceMgr(0) { } + + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info); + }; +} + +void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info) { + Info.Serialize(DiagLevel, OS); +} static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, unsigned argc, char **argv, @@ -122,8 +143,23 @@ Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, // Create the diagnostic client for reporting errors or for // implementing -verify. - llvm::OwningPtr<DiagnosticClient> DiagClient( - new TextDiagnosticPrinter(llvm::errs(), Opts)); + llvm::OwningPtr<DiagnosticClient> DiagClient; + if (Opts.BinaryOutput) { + if (llvm::sys::Program::ChangeStderrToBinary()) { + // We weren't able to set standard error to binary, which is a + // bit of a problem. So, just create a text diagnostic printer + // to complain about this problem, and pretend that the user + // didn't try to use binary output. + DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts)); + Diags->setClient(DiagClient.take()); + Diags->Report(diag::err_fe_stderr_binary); + return Diags.take(); + } else { + DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs())); + } + } else { + DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts)); + } // Chain in -verify checker, if requested. if (Opts.VerifyDiagnostics) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 0bca4754ec11..a193ac870307 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -170,6 +170,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, } if (Opts.NoZeroInitializedInBSS) Res.push_back("-mno-zero-initialized-bss"); + if (Opts.ObjCLegacyDispatch) + Res.push_back("-fobjc-legacy-dispatch"); if (Opts.SoftFloat) Res.push_back("-msoft-float"); if (Opts.UnwindTables) @@ -178,6 +180,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-mrelocation-model"); Res.push_back(Opts.RelocationModel); } + if (!Opts.VerifyModule) + Res.push_back("-disable-llvm-verifier"); } static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, @@ -220,6 +224,8 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-fcolor-diagnostics"); if (Opts.VerifyDiagnostics) Res.push_back("-verify"); + if (Opts.BinaryOutput) + Res.push_back("-fdiagnostics-binary"); if (Opts.ShowOptionNames) Res.push_back("-fdiagnostics-show-option"); if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) { @@ -276,6 +282,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::EmitHTML: return "-emit-html"; case frontend::EmitLLVM: return "-emit-llvm"; case frontend::EmitLLVMOnly: return "-emit-llvm-only"; + case frontend::EmitObj: return "-emit-obj"; case frontend::FixIt: return "-fixit"; case frontend::GeneratePCH: return "-emit-pch"; case frontend::GeneratePTH: return "-emit-pth"; @@ -362,6 +369,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-load"); Res.push_back(Opts.Plugins[i]); } + for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) { + Res.push_back("-ast-merge"); + Res.push_back(Opts.ASTMergeFiles[i]); + } } static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, @@ -450,6 +461,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fms-extensions"); if (Opts.ObjCNonFragileABI) Res.push_back("-fobjc-nonfragile-abi"); + if (Opts.ObjCNonFragileABI2) + Res.push_back("-fobjc-nonfragile-abi2"); // NoInline is implicit. if (!Opts.CXXOperatorNames) Res.push_back("-fno-operator-names"); @@ -465,6 +478,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-faltivec"); if (Opts.Exceptions) Res.push_back("-fexceptions"); + if (Opts.SjLjExceptions) + Res.push_back("-fsjlj-exceptions"); if (!Opts.RTTI) Res.push_back("-fno-rtti"); if (!Opts.NeXTRuntime) @@ -475,8 +490,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fno-builtin"); if (!Opts.AssumeSaneOperatorNew) Res.push_back("-fno-assume-sane-operator-new"); - if (Opts.ThreadsafeStatics) - llvm::llvm_report_error("FIXME: Not yet implemented!"); + if (!Opts.ThreadsafeStatics) + Res.push_back("-fno-threadsafe-statics"); if (Opts.POSIXThreads) Res.push_back("-pthread"); if (Opts.Blocks) @@ -770,18 +785,13 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi); Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision); Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); + Opts.ObjCLegacyDispatch = Args.hasArg(OPT_fobjc_legacy_dispatch); Opts.SoftFloat = Args.hasArg(OPT_msoft_float); Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic"); Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name); - - // FIXME: Put elsewhere? -#ifdef NDEBUG - Opts.VerifyModule = 0; -#else - Opts.VerifyModule = 1; -#endif + Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); } static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, @@ -808,6 +818,7 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option); Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); + Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary); Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop, DiagnosticOptions::DefaultTabStop, Diags); if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { @@ -852,6 +863,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ProgramAction = frontend::EmitLLVM; break; case OPT_emit_llvm_only: Opts.ProgramAction = frontend::EmitLLVMOnly; break; + case OPT_emit_obj: + Opts.ProgramAction = frontend::EmitObj; break; case OPT_fixit: Opts.ProgramAction = frontend::FixIt; break; case OPT_emit_pch: @@ -920,6 +933,7 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ShowTimers = Args.hasArg(OPT_ftime_report); Opts.ShowVersion = Args.hasArg(OPT_version); Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view); + Opts.ASTMergeFiles = getAllArgValues(Args, OPT_ast_merge); FrontendOptions::InputKind DashX = FrontendOptions::IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { @@ -1146,7 +1160,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.Microsoft = Args.hasArg(OPT_fms_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); if (Args.hasArg(OPT_fno_lax_vector_conversions)) - Opts.LaxVectorConversions = 0; + Opts.LaxVectorConversions = 0; + if (Args.hasArg(OPT_fno_threadsafe_statics)) + Opts.ThreadsafeStatics = 0; Opts.Exceptions = Args.hasArg(OPT_fexceptions); Opts.RTTI = !Args.hasArg(OPT_fno_rtti); Opts.Blocks = Args.hasArg(OPT_fblocks); @@ -1165,10 +1181,15 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.ObjCConstantStringClass = getLastArgValue(Args, OPT_fconstant_string_class); Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); + Opts.ObjCNonFragileABI2 = Args.hasArg(OPT_fobjc_nonfragile_abi2); + if (Opts.ObjCNonFragileABI2) + Opts.ObjCNonFragileABI = true; Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); + Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions); Opts.Static = Args.hasArg(OPT_static_define); + Opts.DumpVtableLayouts = Args.hasArg(OPT_fdump_vtable_layouts); Opts.OptimizeSize = 0; // FIXME: Eliminate this dependency. diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 0baba3f4673a..1c958a7087a9 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -177,6 +177,9 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, break; case Backend_EmitNothing: break; + case Backend_EmitObj: + OS.reset(CI.createDefaultOutputFile(true, InFile, "o")); + break; } if (BA != Backend_EmitNothing && !OS) return 0; @@ -196,6 +199,8 @@ EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} +EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {} + //===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp index b163e267b049..f695254cb466 100644 --- a/lib/Frontend/HTMLDiagnostics.cpp +++ b/lib/Frontend/HTMLDiagnostics.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/PathDiagnosticClients.h" -#include "clang/Analysis/PathDiagnostic.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/SourceManager.h" diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 6102760aef53..2e0b4bdbfce3 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -483,10 +483,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddPath("/usr/include/c++/4.1", System, true, false, false); break; case llvm::Triple::Linux: - // Exherbo (2009-10-26) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + // Exherbo (2010-01-25) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", "x86_64-pc-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", "i686-pc-linux-gnu", "", "", triple); // Debian sid AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", @@ -522,6 +522,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", "i686-redhat-linux","", "", triple); + // Fedora 12 (February-2010+) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", + "i686-redhat-linux","", "", triple); + // openSUSE 11.1 32 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", "i586-suse-linux", "", "", triple); diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 9aaf1320346f..b7ab3d8cd452 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -279,6 +279,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.Exceptions) Builder.defineMacro("__EXCEPTIONS"); + if (LangOpts.SjLjExceptions) + Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__"); if (LangOpts.CPlusPlus) { Builder.defineMacro("__DEPRECATED"); diff --git a/lib/Frontend/Makefile b/lib/Frontend/Makefile index 8d708475783f..a630b0133632 100644 --- a/lib/Frontend/Makefile +++ b/lib/Frontend/Makefile @@ -10,7 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangFrontend BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 259355145aa3..a878df784005 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -72,12 +72,14 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c); PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2); PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi); + PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2); PARSE_LANGOPT_BENIGN(PascalStrings); PARSE_LANGOPT_BENIGN(WritableStrings); PARSE_LANGOPT_IMPORTANT(LaxVectorConversions, diag::warn_pch_lax_vector_conversions); PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec); PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions); + PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions); PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime); PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding); PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins); @@ -434,7 +436,9 @@ public: continue; } - Prev->Next = new ObjCMethodList(Method, 0); + ObjCMethodList *Mem = + Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>(); + Prev->Next = new (Mem) ObjCMethodList(Method, 0); Prev = Prev->Next; } @@ -450,7 +454,9 @@ public: continue; } - Prev->Next = new ObjCMethodList(Method, 0); + ObjCMethodList *Mem = + Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>(); + Prev->Next = new (Mem) ObjCMethodList(Method, 0); Prev = Prev->Next; } @@ -1326,6 +1332,14 @@ PCHReader::ReadPCHBlock() { TentativeDefinitions.swap(Record); break; + case pch::UNUSED_STATIC_FUNCS: + if (!UnusedStaticFuncs.empty()) { + Error("duplicate UNUSED_STATIC_FUNCS record in PCH file"); + return Failure; + } + UnusedStaticFuncs.swap(Record); + break; + case pch::LOCALLY_SCOPED_EXTERNAL_DECLS: if (!LocallyScopedExternalDecls.empty()) { Error("duplicate LOCALLY_SCOPED_EXTERNAL_DECLS record in PCH file"); @@ -1400,9 +1414,9 @@ PCHReader::ReadPCHBlock() { break; case pch::VERSION_CONTROL_BRANCH_REVISION: { - llvm::StringRef CurBranch = getClangFullRepositoryVersion(); + const std::string &CurBranch = getClangFullRepositoryVersion(); llvm::StringRef PCHBranch(BlobStart, BlobLen); - if (CurBranch != PCHBranch) { + if (llvm::StringRef(CurBranch) != PCHBranch) { Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch; return IgnorePCH; } @@ -1740,11 +1754,13 @@ bool PCHReader::ParseLanguageOptions( PARSE_LANGOPT(ObjC1); PARSE_LANGOPT(ObjC2); PARSE_LANGOPT(ObjCNonFragileABI); + PARSE_LANGOPT(ObjCNonFragileABI2); PARSE_LANGOPT(PascalStrings); PARSE_LANGOPT(WritableStrings); PARSE_LANGOPT(LaxVectorConversions); PARSE_LANGOPT(AltiVec); PARSE_LANGOPT(Exceptions); + PARSE_LANGOPT(SjLjExceptions); PARSE_LANGOPT(NeXTRuntime); PARSE_LANGOPT(Freestanding); PARSE_LANGOPT(NoBuiltin); @@ -1880,18 +1896,20 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { } case pch::TYPE_VECTOR: { - if (Record.size() != 2) { + if (Record.size() != 4) { Error("incorrect encoding of vector type in PCH file"); return QualType(); } QualType ElementType = GetType(Record[0]); unsigned NumElements = Record[1]; - return Context->getVectorType(ElementType, NumElements); + bool AltiVec = Record[2]; + bool Pixel = Record[3]; + return Context->getVectorType(ElementType, NumElements, AltiVec, Pixel); } case pch::TYPE_EXT_VECTOR: { - if (Record.size() != 2) { + if (Record.size() != 4) { Error("incorrect encoding of extended vector type in PCH file"); return QualType(); } @@ -2464,11 +2482,17 @@ void PCHReader::InitializeSema(Sema &S) { PreloadedDecls.clear(); // If there were any tentative definitions, deserialize them and add - // them to Sema's table of tentative definitions. + // them to Sema's list of tentative definitions. for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I])); - SemaObj->TentativeDefinitions[Var->getDeclName()] = Var; - SemaObj->TentativeDefinitionList.push_back(Var->getDeclName()); + SemaObj->TentativeDefinitions.push_back(Var); + } + + // If there were any unused static functions, deserialize them and add to + // Sema's list of unused static functions. + for (unsigned I = 0, N = UnusedStaticFuncs.size(); I != N; ++I) { + FunctionDecl *FD = cast<FunctionDecl>(GetDecl(UnusedStaticFuncs[I])); + SemaObj->UnusedStaticFuncs.push_back(FD); } // If there were any locally-scoped external declarations, diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 4dc1318a3ee8..625997cac232 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -117,6 +117,7 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) { cast_or_null<TagDecl>(Reader.GetDecl(Record[Idx++]))); TD->setTagKind((TagDecl::TagKind)Record[Idx++]); TD->setDefinition(Record[Idx++]); + TD->setEmbeddedInDeclarator(Record[Idx++]); TD->setTypedefForAnonDecl( cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++]))); TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -179,7 +180,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); - FD->setParams(*Reader.getContext(), Params.data(), NumParams); + FD->setParams(Params.data(), NumParams); } void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { @@ -387,7 +388,7 @@ void PCHDeclReader::VisitVarDecl(VarDecl *VD) { VD->setPreviousDeclaration( cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); if (Record[Idx++]) - VD->setInit(*Reader.getContext(), Reader.ReadDeclExpr()); + VD->setInit(Reader.ReadDeclExpr()); } void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { @@ -412,7 +413,7 @@ void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) { Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); - BD->setParams(*Reader.getContext(), Params.data(), NumParams); + BD->setParams(Params.data(), NumParams); } std::pair<uint64_t, uint64_t> @@ -445,7 +446,7 @@ Attr *PCHReader::ReadAttributes() { #define STRING_ATTR(Name) \ case Attr::Name: \ - New = ::new (*Context) Name##Attr(ReadString(Record, Idx)); \ + New = ::new (*Context) Name##Attr(*Context, ReadString(Record, Idx)); \ break #define UNSIGNED_ATTR(Name) \ @@ -496,7 +497,7 @@ Attr *PCHReader::ReadAttributes() { std::string Type = ReadString(Record, Idx); unsigned FormatIdx = Record[Idx++]; unsigned FirstArg = Record[Idx++]; - New = ::new (*Context) FormatAttr(Type, FormatIdx, FirstArg); + New = ::new (*Context) FormatAttr(*Context, Type, FormatIdx, FirstArg); break; } @@ -531,7 +532,7 @@ Attr *PCHReader::ReadAttributes() { llvm::SmallVector<unsigned, 16> ArgNums; ArgNums.insert(ArgNums.end(), &Record[Idx], &Record[Idx] + Size); Idx += Size; - New = ::new (*Context) NonNullAttr(ArgNums.data(), Size); + New = ::new (*Context) NonNullAttr(*Context, ArgNums.data(), Size); break; } diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 21c9cbf17cd7..d123694d699d 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -123,6 +123,8 @@ namespace { unsigned VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); unsigned VisitCXXConstCastExpr(CXXConstCastExpr *E); unsigned VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); + unsigned VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); + unsigned VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); }; } @@ -317,22 +319,24 @@ unsigned PCHStmtReader::VisitAsmStmt(AsmStmt *S) { S->setAsmString(cast_or_null<StringLiteral>(StmtStack[StackIdx++])); // Outputs and inputs - llvm::SmallVector<std::string, 16> Names; + llvm::SmallVector<IdentifierInfo *, 16> Names; llvm::SmallVector<StringLiteral*, 16> Constraints; llvm::SmallVector<Stmt*, 16> Exprs; for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) { - Names.push_back(Reader.ReadString(Record, Idx)); + Names.push_back(Reader.GetIdentifierInfo(Record, Idx)); Constraints.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++])); Exprs.push_back(StmtStack[StackIdx++]); } - S->setOutputsAndInputs(NumOutputs, NumInputs, - Names.data(), Constraints.data(), Exprs.data()); // Constraints llvm::SmallVector<StringLiteral*, 16> Clobbers; for (unsigned I = 0; I != NumClobbers; ++I) Clobbers.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++])); - S->setClobbers(Clobbers.data(), NumClobbers); + + S->setOutputsAndInputsAndClobbers(*Reader.getContext(), + Names.data(), Constraints.data(), + Exprs.data(), NumOutputs, NumInputs, + Clobbers.data(), NumClobbers); assert(StackIdx == StmtStack.size() && "Error deserializing AsmStmt"); return NumOutputs*2 + NumInputs*2 + NumClobbers + 1; @@ -904,6 +908,19 @@ unsigned PCHStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { return num; } +unsigned PCHStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { + VisitExpr(E); + E->setValue(Record[Idx++]); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { + VisitExpr(E); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + // Within the bitstream, expressions are stored in Reverse Polish // Notation, with each of the subexpressions preceding the // expression they are stored in. To evaluate expressions, we @@ -1233,7 +1250,13 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { S = new (Context) CXXFunctionalCastExpr(Empty); break; + case pch::EXPR_CXX_BOOL_LITERAL: + S = new (Context) CXXBoolLiteralExpr(Empty); + break; + case pch::EXPR_CXX_NULL_PTR_LITERAL: + S = new (Context) CXXNullPtrLiteralExpr(Empty); + break; } // We hit a STMT_STOP, so we're done with this expression. diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 9909c95847ee..4c99dbe24504 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -128,6 +128,8 @@ void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) { void PCHTypeWriter::VisitVectorType(const VectorType *T) { Writer.AddTypeRef(T->getElementType(), Record); Record.push_back(T->getNumElements()); + Record.push_back(T->isAltiVec()); + Record.push_back(T->isPixel()); Code = pch::TYPE_VECTOR; } @@ -511,6 +513,15 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream, RECORD(STMT_OBJC_AT_TRY); RECORD(STMT_OBJC_AT_SYNCHRONIZED); RECORD(STMT_OBJC_AT_THROW); + RECORD(EXPR_CXX_OPERATOR_CALL); + RECORD(EXPR_CXX_CONSTRUCT); + RECORD(EXPR_CXX_STATIC_CAST); + RECORD(EXPR_CXX_DYNAMIC_CAST); + RECORD(EXPR_CXX_REINTERPRET_CAST); + RECORD(EXPR_CXX_CONST_CAST); + RECORD(EXPR_CXX_FUNCTIONAL_CAST); + RECORD(EXPR_CXX_BOOL_LITERAL); + RECORD(EXPR_CXX_NULL_PTR_LITERAL); #undef RECORD } @@ -534,6 +545,7 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(SPECIAL_TYPES); RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); + RECORD(UNUSED_STATIC_FUNCS); RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS); RECORD(SELECTOR_OFFSETS); RECORD(METHOD_POOL); @@ -737,13 +749,17 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled. Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled. - Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C modern abi enabled + Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C + // modern abi enabled. + Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced + // modern abi enabled. Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings Record.push_back(LangOpts.WritableStrings); // Allow writable strings Record.push_back(LangOpts.LaxVectorConversions); Record.push_back(LangOpts.AltiVec); Record.push_back(LangOpts.Exceptions); // Support exception handling. + Record.push_back(LangOpts.SjLjExceptions); Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime. Record.push_back(LangOpts.Freestanding); // Freestanding implementation @@ -1960,15 +1976,18 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, } // Build a record containing all of the tentative definitions in this file, in - // TentativeDefinitionList order. Generally, this record will be empty for + // TentativeDefinitions order. Generally, this record will be empty for // headers. RecordData TentativeDefinitions; - for (unsigned i = 0, e = SemaRef.TentativeDefinitionList.size(); i != e; ++i){ - VarDecl *VD = - SemaRef.TentativeDefinitions.lookup(SemaRef.TentativeDefinitionList[i]); - if (VD) AddDeclRef(VD, TentativeDefinitions); + for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) { + AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions); } + // Build a record containing all of the static unused functions in this file. + RecordData UnusedStaticFuncs; + for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i) + AddDeclRef(SemaRef.UnusedStaticFuncs[i], UnusedStaticFuncs); + // Build a record containing all of the locally-scoped external // declarations in this header file. Generally, this record will be // empty. @@ -2070,6 +2089,10 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, if (!TentativeDefinitions.empty()) Stream.EmitRecord(pch::TENTATIVE_DEFINITIONS, TentativeDefinitions); + // Write the record containing unused static functions. + if (!UnusedStaticFuncs.empty()) + Stream.EmitRecord(pch::UNUSED_STATIC_FUNCS, UnusedStaticFuncs); + // Write the record containing locally-scoped external definitions. if (!LocallyScopedExternalDecls.empty()) Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS, diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 020f69b3e669..d105382b4354 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -115,6 +115,7 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) { Writer.AddDeclRef(D->getPreviousDeclaration(), Record); Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding Record.push_back(D->isDefinition()); + Record.push_back(D->isEmbeddedInDeclarator()); Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record); Writer.AddSourceLocation(D->getRBraceLoc(), Record); Writer.AddSourceLocation(D->getTagKeywordLoc(), Record); diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index fdfdfefe08ef..a8cc9d6f4591 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -118,6 +118,8 @@ namespace { void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); void VisitCXXConstCastExpr(CXXConstCastExpr *E); void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); + void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); + void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); }; } @@ -287,15 +289,15 @@ void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) { Writer.WriteSubStmt(S->getAsmString()); // Outputs - for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { - Writer.AddString(S->getOutputName(I), Record); + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + Writer.AddIdentifierRef(S->getOutputIdentifier(I), Record); Writer.WriteSubStmt(S->getOutputConstraintLiteral(I)); Writer.WriteSubStmt(S->getOutputExpr(I)); } // Inputs for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { - Writer.AddString(S->getInputName(I), Record); + Writer.AddIdentifierRef(S->getInputIdentifier(I), Record); Writer.WriteSubStmt(S->getInputConstraintLiteral(I)); Writer.WriteSubStmt(S->getInputExpr(I)); } @@ -834,6 +836,19 @@ void PCHStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { Code = pch::EXPR_CXX_FUNCTIONAL_CAST; } +void PCHStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { + VisitExpr(E); + Record.push_back(E->getValue()); + Writer.AddSourceLocation(E->getLocation(), Record); + Code = pch::EXPR_CXX_BOOL_LITERAL; +} + +void PCHStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getLocation(), Record); + Code = pch::EXPR_CXX_NULL_PTR_LITERAL; +} + //===----------------------------------------------------------------------===// // PCHWriter Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 98be869d2646..5706a07e5a0f 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/PathDiagnosticClients.h" -#include "clang/Analysis/PathDiagnostic.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Lex/Preprocessor.h" diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index a91dd8d55e92..8d64a6413304 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -391,7 +391,7 @@ namespace { bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, - std::string *Names, + IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, ExprArg AsmString, @@ -684,7 +684,8 @@ namespace { virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, IdentifierInfo *Ident, - SourceLocation LBrace) { + SourceLocation LBrace, + AttributeList *AttrList) { Out << __FUNCTION__ << "\n"; return DeclPtrTy(); } diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 35d8dde8eaab..9dade66d4ab4 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -124,8 +124,10 @@ namespace { llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs; // Block related declarations. - llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls; - llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls; + llvm::SmallVector<ValueDecl *, 8> BlockByCopyDecls; + llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet; + llvm::SmallVector<ValueDecl *, 8> BlockByRefDecls; + llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet; llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo; llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; @@ -212,11 +214,10 @@ namespace { << Old->getSourceRange(); } - void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen, + void InsertText(SourceLocation Loc, llvm::StringRef Str, bool InsertAfter = true) { // If insertion succeeded or warning disabled return with no warning. - if (!Rewrite.InsertText(Loc, llvm::StringRef(StrData, StrLen), - InsertAfter) || + if (!Rewrite.InsertText(Loc, Str, InsertAfter) || SilenceRewriteMacroWarning) return; @@ -232,10 +233,9 @@ namespace { } void ReplaceText(SourceLocation Start, unsigned OrigLength, - const char *NewStr, unsigned NewLength) { + llvm::StringRef Str) { // If removal succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(Start, OrigLength, - llvm::StringRef(NewStr, NewLength)) || + if (!Rewrite.ReplaceText(Start, OrigLength, Str) || SilenceRewriteMacroWarning) return; @@ -263,6 +263,7 @@ namespace { void RewriteFunctionDecl(FunctionDecl *FD); void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); + void RewriteTypeOfDecl(VarDecl *VD); void RewriteObjCQualifiedInterfaceTypes(Expr *E); bool needToScanForQualifiers(QualType T); ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr); @@ -278,7 +279,9 @@ namespace { ParentMap *PropParentMap; // created lazily. Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); - Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart); + Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart, + bool &replaced); + Stmt *RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced); Stmt *RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr); Stmt *RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, SourceRange SrcRange); @@ -632,6 +635,9 @@ void RewriteObjC::Initialize(ASTContext &context) { //===----------------------------------------------------------------------===// void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { + if (Diags.hasErrorOccurred()) + return; + // Two cases: either the decl could be in the main file, or it could be in a // #included file. If the former, rewrite it now. If the later, check to see // if we rewrote the #include/#import. @@ -681,7 +687,6 @@ void RewriteObjC::RewriteInclude() { const char *MainBufStart = MainBuf.first; const char *MainBufEnd = MainBuf.second; size_t ImportLen = strlen("import"); - size_t IncludeLen = strlen("include"); // Loop over the whole file, looking for includes. for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) { @@ -695,7 +700,7 @@ void RewriteObjC::RewriteInclude() { // replace import with include SourceLocation ImportLoc = LocStart.getFileLocWithOffset(BufPtr-MainBufStart); - ReplaceText(ImportLoc, ImportLen, "include", IncludeLen); + ReplaceText(ImportLoc, ImportLen, "include"); BufPtr += ImportLen; } } @@ -728,7 +733,7 @@ void RewriteObjC::RewriteTabs() { TabLoc = TabLoc.getFileLocWithOffset(BufPtr-MainBufStart); // Rewrite the single tab character into a sequence of spaces. - ReplaceText(TabLoc, 1, " ", Spaces); + ReplaceText(TabLoc, 1, llvm::StringRef(" ", Spaces)); } } @@ -746,7 +751,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, ObjCImplementationDecl *IMD, ObjCCategoryImplDecl *CID) { SourceLocation startLoc = PID->getLocStart(); - InsertText(startLoc, "// ", 3); + InsertText(startLoc, "// "); const char *startBuf = SM->getCharacterData(startLoc); assert((*startBuf == '@') && "bogus @synthesize location"); const char *semiBuf = strchr(startBuf, ';'); @@ -774,7 +779,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, // See objc-act.c:objc_synthesize_new_getter() for details. Getr += "return " + getIvarAccessString(ClassDecl, OID); Getr += "; }"; - InsertText(onePastSemiLoc, Getr.c_str(), Getr.size()); + InsertText(onePastSemiLoc, Getr); if (PD->isReadOnly()) return; @@ -789,7 +794,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, Setr += getIvarAccessString(ClassDecl, OID) + " = "; Setr += PD->getNameAsCString(); Setr += "; }"; - InsertText(onePastSemiLoc, Setr.c_str(), Setr.size()); + InsertText(onePastSemiLoc, Setr); } void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { @@ -828,8 +833,7 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { } // Replace the @class with typedefs corresponding to the classes. - ReplaceText(startLoc, semiPtr-startBuf+1, - typedefString.c_str(), typedefString.size()); + ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); } void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { @@ -842,17 +846,17 @@ void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { if (SM->getInstantiationLineNumber(LocEnd) > SM->getInstantiationLineNumber(LocStart)) { - InsertText(LocStart, "#if 0\n", 6); - ReplaceText(LocEnd, 1, ";\n#endif\n", 9); + InsertText(LocStart, "#if 0\n"); + ReplaceText(LocEnd, 1, ";\n#endif\n"); } else { - InsertText(LocStart, "// ", 3); + InsertText(LocStart, "// "); } } void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) { SourceLocation Loc = prop->getAtLoc(); - ReplaceText(Loc, 0, "// ", 3); + ReplaceText(Loc, 0, "// "); // FIXME: handle properties that are declared across multiple lines. } @@ -860,8 +864,12 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { SourceLocation LocStart = CatDecl->getLocStart(); // FIXME: handle category headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// ", 3); + ReplaceText(LocStart, 0, "// "); + for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(), + E = CatDecl->prop_end(); I != E; ++I) + RewriteProperty(*I); + for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); I != E; ++I) @@ -872,7 +880,7 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { RewriteMethodDeclaration(*I); // Lastly, comment out the @end. - ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// ", 3); + ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// "); } void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { @@ -881,7 +889,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { SourceLocation LocStart = PDecl->getLocStart(); // FIXME: handle protocol headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// ", 3); + ReplaceText(LocStart, 0, "// "); for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); @@ -894,24 +902,20 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { // Lastly, comment out the @end. SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); - ReplaceText(LocEnd, 0, "// ", 3); + ReplaceText(LocEnd, 0, "// "); // Must comment out @optional/@required const char *startBuf = SM->getCharacterData(LocStart); const char *endBuf = SM->getCharacterData(LocEnd); for (const char *p = startBuf; p < endBuf; p++) { if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { - std::string CommentedOptional = "/* @optional */"; SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@optional"), - CommentedOptional.c_str(), CommentedOptional.size()); + ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */"); } else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { - std::string CommentedRequired = "/* @required */"; SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@required"), - CommentedRequired.c_str(), CommentedRequired.size()); + ReplaceText(OptionalLoc, strlen("@required"), "/* @required */"); } } @@ -922,7 +926,7 @@ void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) { if (LocStart.isInvalid()) assert(false && "Invalid SourceLocation"); // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// ", 3); + ReplaceText(LocStart, 0, "// "); } void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD, @@ -1050,10 +1054,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) { ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID); ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID); - if (IMD) - InsertText(IMD->getLocStart(), "// ", 3); - else - InsertText(CID->getLocStart(), "// ", 3); + InsertText(IMD ? IMD->getLocStart() : CID->getLocStart(), "// "); for (ObjCCategoryImplDecl::instmeth_iterator I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(), @@ -1067,8 +1068,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) { const char *startBuf = SM->getCharacterData(LocStart); const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, - ResultStr.c_str(), ResultStr.size()); + ReplaceText(LocStart, endBuf-startBuf, ResultStr); } for (ObjCCategoryImplDecl::classmeth_iterator @@ -1083,8 +1083,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) { const char *startBuf = SM->getCharacterData(LocStart); const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, - ResultStr.c_str(), ResultStr.size()); + ReplaceText(LocStart, endBuf-startBuf, ResultStr); } for (ObjCCategoryImplDecl::propimpl_iterator I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(), @@ -1093,10 +1092,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) { RewritePropertyImplDecl(*I, IMD, CID); } - if (IMD) - InsertText(IMD->getLocEnd(), "// ", 3); - else - InsertText(CID->getLocEnd(), "// ", 3); + InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// "); } void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { @@ -1130,7 +1126,7 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { RewriteMethodDeclaration(*I); // Lastly, comment out the @end. - ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// ", 3); + ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// "); } Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, @@ -1149,7 +1145,7 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, // This allows us to handle chain/nested property getters. Receiver = PropGetters[PRE]; } - MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver), + MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver), PDecl->getSetterName(), PDecl->getType(), PDecl->getSetterMethodDecl(), SourceLocation(), SourceLocation(), @@ -1178,7 +1174,7 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) { // This allows us to handle chain/nested property getters. Receiver = PropGetters[PRE]; } - MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver), + MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver), PDecl->getGetterName(), PDecl->getType(), PDecl->getGetterMethodDecl(), SourceLocation(), SourceLocation(), @@ -1209,14 +1205,15 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) { } Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, - SourceLocation OrigStart) { + SourceLocation OrigStart, + bool &replaced) { ObjCIvarDecl *D = IV->getDecl(); const Expr *BaseExpr = IV->getBase(); if (CurMethodDef) { - if (BaseExpr->getType()->isObjCObjectPointerType() && - isa<DeclRefExpr>(BaseExpr)) { + if (BaseExpr->getType()->isObjCObjectPointerType()) { ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType()); + assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null"); // lookup which class implements the instance variable. ObjCInterfaceDecl *clsDeclared = 0; iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), @@ -1226,7 +1223,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, // Synthesize an explicit cast to gain access to the ivar. std::string RecName = clsDeclared->getIdentifier()->getName(); RecName += "_IMPL"; - IdentifierInfo *II = &Context->Idents.get(RecName.c_str()); + IdentifierInfo *II = &Context->Idents.get(RecName); RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, SourceLocation(), II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); @@ -1238,17 +1235,16 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), IV->getBase()->getLocEnd(), castExpr); + replaced = true; if (IV->isFreeIvar() && CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) { MemberExpr *ME = new (Context) MemberExpr(PE, true, D, IV->getLocation(), D->getType()); - ReplaceStmt(IV, ME); // delete IV; leak for now, see RewritePropertySetter() usage for more info. return ME; } - - ReplaceStmt(IV->getBase(), PE); + // Get the new text // Cannot delete IV->getBase(), since PE points to it. // Replace the old base with the cast. This is important when doing // embedded rewrites. For example, [newInv->_container addObject:0]. @@ -1272,7 +1268,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, // Synthesize an explicit cast to gain access to the ivar. std::string RecName = clsDeclared->getIdentifier()->getName(); RecName += "_IMPL"; - IdentifierInfo *II = &Context->Idents.get(RecName.c_str()); + IdentifierInfo *II = &Context->Idents.get(RecName); RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, SourceLocation(), II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); @@ -1283,7 +1279,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), IV->getBase()->getLocEnd(), castExpr); - ReplaceStmt(IV->getBase(), PE); + replaced = true; // Cannot delete IV->getBase(), since PE points to it. // Replace the old base with the cast. This is important when doing // embedded rewrites. For example, [newInv->_container addObject:0]. @@ -1294,6 +1290,28 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, return IV; } +Stmt *RewriteObjC::RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced) { + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) { + if (*CI) { + Stmt *newStmt = RewriteObjCNestedIvarRefExpr(*CI, replaced); + if (newStmt) + *CI = newStmt; + } + } + if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) { + SourceRange OrigStmtRange = S->getSourceRange(); + Stmt *newStmt = RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin(), + replaced); + return newStmt; + } + if (ObjCMessageExpr *MsgRefExpr = dyn_cast<ObjCMessageExpr>(S)) { + Stmt *newStmt = SynthMessageExpr(MsgRefExpr); + return newStmt; + } + return S; +} + /// SynthCountByEnumWithState - To print: /// ((unsigned int (*) /// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) @@ -1326,7 +1344,7 @@ Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) { SourceLocation startLoc = S->getLocStart(); buf = "goto __break_label_"; buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("break"), buf.c_str(), buf.size()); + ReplaceText(startLoc, strlen("break"), buf); return 0; } @@ -1343,7 +1361,7 @@ Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) { SourceLocation startLoc = S->getLocStart(); buf = "goto __continue_label_"; buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("continue"), buf.c_str(), buf.size()); + ReplaceText(startLoc, strlen("continue"), buf); return 0; } @@ -1442,8 +1460,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, startCollectionBuf += 3; // Replace: "for (type element in" with string constructed thus far. - ReplaceText(startLoc, startCollectionBuf - startBuf, - buf.c_str(), buf.size()); + ReplaceText(startLoc, startCollectionBuf - startBuf, buf); // Replace ')' in for '(' type elem in collection ')' with ';' SourceLocation rightParenLoc = S->getRParenLoc(); const char *rparenBuf = SM->getCharacterData(rightParenLoc); @@ -1484,7 +1501,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, buf += elementTypeAsString; buf += ")enumState.itemsPtr[counter++];"; // Replace ')' in for '(' type elem in collection ')' with all of these. - ReplaceText(lparenLoc, 1, buf.c_str(), buf.size()); + ReplaceText(lparenLoc, 1, buf); /// __continue_label: ; /// } while (counter < limit); @@ -1525,7 +1542,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, // FIXME: If this should support Obj-C++, support CXXTryStmt if (isa<CompoundStmt>(S->getBody())) { SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1); - InsertText(endBodyLoc, buf.c_str(), buf.size()); + InsertText(endBodyLoc, buf); } else { /* Need to treat single statements specially. For example: * @@ -1538,7 +1555,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, const char *semiBuf = strchr(stmtBuf, ';'); assert(semiBuf && "Can't find ';'"); SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(semiBuf-stmtBuf+1); - InsertText(endBodyLoc, buf.c_str(), buf.size()); + InsertText(endBodyLoc, buf); } Stmts.pop_back(); ObjCBcLabelNo.pop_back(); @@ -1562,7 +1579,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { buf = "objc_sync_enter((id)"; const char *lparenBuf = startBuf; while (*lparenBuf != '(') lparenBuf++; - ReplaceText(startLoc, lparenBuf-startBuf+1, buf.c_str(), buf.size()); + ReplaceText(startLoc, lparenBuf-startBuf+1, buf); // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since // the sync expression is typically a message expression that's already // been rewritten! (which implies the SourceLocation's are invalid). @@ -1578,7 +1595,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { buf += "id volatile _rethrow = 0;\n"; buf += "objc_exception_try_enter(&_stack);\n"; buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; - ReplaceText(rparenLoc, 1, buf.c_str(), buf.size()); + ReplaceText(rparenLoc, 1, buf); startLoc = S->getSynchBody()->getLocEnd(); startBuf = SM->getCharacterData(startLoc); @@ -1607,7 +1624,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { buf += "}\n"; buf += "}"; - ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); + ReplaceText(lastCurlyLoc, 1, buf); bool hasReturns = false; HasReturnStmts(S->getSynchBody(), hasReturns); @@ -1663,8 +1680,8 @@ void RewriteObjC::RewriteTryReturnStmts(Stmt *S) { std::string buf; buf = "{ objc_exception_try_exit(&_stack); return"; - ReplaceText(startLoc, 6, buf.c_str(), buf.size()); - InsertText(onePastSemiLoc, "}", 1); + ReplaceText(startLoc, 6, buf); + InsertText(onePastSemiLoc, "}"); } return; } @@ -1689,8 +1706,8 @@ void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) { buf += syncExitBuf; buf += " return"; - ReplaceText(startLoc, 6, buf.c_str(), buf.size()); - InsertText(onePastSemiLoc, "}", 1); + ReplaceText(startLoc, 6, buf); + InsertText(onePastSemiLoc, "}"); } return; } @@ -1711,7 +1728,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { buf += "objc_exception_try_enter(&_stack);\n"; buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; - ReplaceText(startLoc, 4, buf.c_str(), buf.size()); + ReplaceText(startLoc, 4, buf); startLoc = S->getTryBody()->getLocEnd(); startBuf = SM->getCharacterData(startLoc); @@ -1729,12 +1746,12 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { buf += " _rethrow = objc_exception_extract(&_stack);\n"; buf += " else { /* @catch continue */"; - InsertText(startLoc, buf.c_str(), buf.size()); + InsertText(startLoc, buf); } else { /* no catch list */ buf = "}\nelse {\n"; buf += " _rethrow = objc_exception_extract(&_stack);\n"; buf += "}"; - ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); + ReplaceText(lastCurlyLoc, 1, buf); } bool sawIdTypedCatch = false; Stmt *lastCatchBody = 0; @@ -1767,7 +1784,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { QualType t = catchDecl->getType(); if (t == Context->getObjCIdType()) { buf += "1) { "; - ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size()); + ReplaceText(startLoc, lParenLoc-startBuf+1, buf); sawIdTypedCatch = true; } else if (t->isObjCObjectPointerType()) { QualType InterfaceTy = t->getPointeeType(); @@ -1777,7 +1794,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { buf += "objc_exception_match((struct objc_class *)objc_getClass(\""; buf += cls->getDecl()->getNameAsString(); buf += "\"), (struct objc_object *)_caught)) { "; - ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size()); + ReplaceText(startLoc, lParenLoc-startBuf+1, buf); } } // Now rewrite the body... @@ -1789,10 +1806,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { assert((*rParenBuf == ')') && "bogus @catch paren location"); assert((*bodyBuf == '{') && "bogus @catch body location"); - buf = " = _caught;"; // Here we replace ") {" with "= _caught;" (which initializes and // declares the @catch parameter). - ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, buf.c_str(), buf.size()); + ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;"); } else { assert(false && "@catch rewrite bug"); } @@ -1814,7 +1830,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { buf += "} } /* @catch end */\n"; if (!S->getFinallyStmt()) buf += "}\n"; - InsertText(bodyLoc, buf.c_str(), buf.size()); + InsertText(bodyLoc, buf); // Set lastCurlyLoc lastCurlyLoc = lastCatchBody->getLocEnd(); @@ -1824,8 +1840,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { startBuf = SM->getCharacterData(startLoc); assert((*startBuf == '@') && "bogus @finally start"); - buf = "/* @finally */"; - ReplaceText(startLoc, 8, buf.c_str(), buf.size()); + ReplaceText(startLoc, 8, "/* @finally */"); Stmt *body = finalStmt->getFinallyBody(); SourceLocation startLoc = body->getLocStart(); @@ -1836,11 +1851,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { "bogus @finally body location"); startLoc = startLoc.getFileLocWithOffset(1); - buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - InsertText(startLoc, buf.c_str(), buf.size()); + InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n"); endLoc = endLoc.getFileLocWithOffset(-1); - buf = " if (_rethrow) objc_exception_throw(_rethrow);\n"; - InsertText(endLoc, buf.c_str(), buf.size()); + InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n"); // Set lastCurlyLoc lastCurlyLoc = body->getLocEnd(); @@ -1852,7 +1865,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; buf += "}"; - ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); + ReplaceText(lastCurlyLoc, 1, buf); // Now check for any return/continue/go statements within the @try. // The implicit finally clause won't called if the @try contains any @@ -1864,8 +1877,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { } // Now emit the final closing curly brace... lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1); - buf = " } /* @try scope end */\n"; - InsertText(lastCurlyLoc, buf.c_str(), buf.size()); + InsertText(lastCurlyLoc, " } /* @try scope end */\n"); return 0; } @@ -1897,13 +1909,12 @@ Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { // handle "@ throw" correctly. const char *wBuf = strchr(startBuf, 'w'); assert((*wBuf == 'w') && "@throw: can't find 'w'"); - ReplaceText(startLoc, wBuf-startBuf+1, buf.c_str(), buf.size()); + ReplaceText(startLoc, wBuf-startBuf+1, buf); const char *semiBuf = strchr(startBuf, ';'); assert((*semiBuf == ';') && "@throw: can't find ';'"); SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf); - buf = ");"; - ReplaceText(semiLoc, 1, buf.c_str(), buf.size()); + ReplaceText(semiLoc, 1, ");"); return 0; } @@ -1991,7 +2002,17 @@ static void scanToNextArgument(const char *&argRef) { } bool RewriteObjC::needToScanForQualifiers(QualType T) { - return T->isObjCQualifiedIdType() || T->isObjCQualifiedInterfaceType(); + if (T->isObjCQualifiedIdType()) + return true; + if (const PointerType *PT = T->getAs<PointerType>()) { + if (PT->getPointeeType()->isObjCQualifiedIdType()) + return true; + } + if (T->isObjCObjectPointerType()) { + T = T->getPointeeType(); + return T->isObjCQualifiedInterfaceType(); + } + return false; } void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { @@ -2018,8 +2039,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf); SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1); // Comment out the protocol references. - InsertText(LessLoc, "/*", 2); - InsertText(GreaterLoc, "*/", 2); + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); } } } @@ -2063,8 +2084,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf); SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1); // Comment out the protocol references. - InsertText(LessLoc, "/*", 2); - InsertText(GreaterLoc, "*/", 2); + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); } } if (!proto) @@ -2087,8 +2108,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startFuncBuf+1); // Comment out the protocol references. - InsertText(LessLoc, "/*", 2); - InsertText(GreaterLoc, "*/", 2); + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); } startBuf = ++endBuf; } @@ -2102,6 +2123,42 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { } } +void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) { + QualType QT = ND->getType(); + const Type* TypePtr = QT->getAs<Type>(); + if (!isa<TypeOfExprType>(TypePtr)) + return; + while (isa<TypeOfExprType>(TypePtr)) { + const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr); + QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); + TypePtr = QT->getAs<Type>(); + } + // FIXME. This will not work for multiple declarators; as in: + // __typeof__(a) b,c,d; + std::string TypeAsString(QT.getAsString()); + SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + const char *startBuf = SM->getCharacterData(DeclLoc); + if (ND->getInit()) { + std::string Name(ND->getNameAsString()); + TypeAsString += " " + Name + " = "; + Expr *E = ND->getInit(); + SourceLocation startLoc; + if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) + startLoc = ECE->getLParenLoc(); + else + startLoc = E->getLocStart(); + startLoc = SM->getInstantiationLoc(startLoc); + const char *endBuf = SM->getCharacterData(startLoc); + ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); + } + else { + SourceLocation X = ND->getLocEnd(); + X = SM->getInstantiationLoc(X); + const char *endBuf = SM->getCharacterData(X); + ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); + } +} + // SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); void RewriteObjC::SynthSelGetUidFunctionDecl() { IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); @@ -2126,6 +2183,19 @@ void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { RewriteObjCQualifiedInterfaceTypes(FD); } +static void RewriteBlockPointerType(std::string& Str, QualType Type) { + std::string TypeString(Type.getAsString()); + const char *argPtr = TypeString.c_str(); + if (!strchr(argPtr, '^')) { + Str += TypeString; + return; + } + while (*argPtr) { + Str += (*argPtr == '^' ? '*' : *argPtr); + argPtr++; + } +} + void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); const FunctionType *funcType = FD->getType()->getAs<FunctionType>(); @@ -2140,13 +2210,12 @@ void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { unsigned numArgs = proto->getNumArgs(); for (unsigned i = 0; i < numArgs; i++) { QualType ArgType = proto->getArgType(i); - FdStr += ArgType.getAsString(); - + RewriteBlockPointerType(FdStr, ArgType); if (i+1 < numArgs) FdStr += ", "; } FdStr += ");\n"; - InsertText(FunLocStart, FdStr.c_str(), FdStr.size()); + InsertText(FunLocStart, FdStr); CurFunctionDeclToDeclareForBlock = 0; } @@ -2330,7 +2399,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - &Context->Idents.get(S.c_str()), strType, 0, + &Context->Idents.get(S), strType, 0, VarDecl::Static); DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation()); Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, @@ -2380,7 +2449,7 @@ QualType RewriteObjC::getSuperStructType() { /*Mutable=*/false)); } - SuperStructDecl->completeDefinition(*Context); + SuperStructDecl->completeDefinition(); } return Context->getTagDeclType(SuperStructDecl); } @@ -2411,7 +2480,7 @@ QualType RewriteObjC::getConstantStringStructType() { /*Mutable=*/true)); } - ConstantStringDecl->completeDefinition(*Context); + ConstantStringDecl->completeDefinition(); } return Context->getTagDeclType(ConstantStringDecl); } @@ -2871,7 +2940,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, if ((CDecl->isForwardDecl() || NumIvars == 0) && (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); - ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size()); + ReplaceText(LocStart, endBuf-startBuf, Result); return; } @@ -2913,10 +2982,10 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, endHeader++; } // rewrite the original header - ReplaceText(LocStart, endHeader-startBuf, Result.c_str(), Result.size()); + ReplaceText(LocStart, endHeader-startBuf, Result); } else { // rewrite the original header *without* disturbing the '{' - ReplaceText(LocStart, cursor-startBuf, Result.c_str(), Result.size()); + ReplaceText(LocStart, cursor-startBuf, Result); } if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { Result = "\n struct "; @@ -2928,7 +2997,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, // insert the super class structure definition. SourceLocation OnePastCurly = LocStart.getFileLocWithOffset(cursor-startBuf+1); - InsertText(OnePastCurly, Result.c_str(), Result.size()); + InsertText(OnePastCurly, Result); } cursor++; // past '{' @@ -2946,26 +3015,26 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, !strncmp(cursor, "private", strlen("private")) || !strncmp(cursor, "package", strlen("package")) || !strncmp(cursor, "protected", strlen("protected"))) - InsertText(atLoc, "// ", 3); + InsertText(atLoc, "// "); } // FIXME: If there are cases where '<' is used in ivar declaration part // of user code, then scan the ivar list and use needToScanForQualifiers // for type checking. else if (*cursor == '<') { SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); - InsertText(atLoc, "/* ", 3); + InsertText(atLoc, "/* "); cursor = strchr(cursor, '>'); cursor++; atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); - InsertText(atLoc, " */", 3); + InsertText(atLoc, " */"); } else if (*cursor == '^') { // rewrite block specifier. SourceLocation caretLoc = LocStart.getFileLocWithOffset(cursor-startBuf); - ReplaceText(caretLoc, 1, "*", 1); + ReplaceText(caretLoc, 1, "*"); } cursor++; } // Don't forget to add a ';'!! - InsertText(LocEnd.getFileLocWithOffset(1), ";", 1); + InsertText(LocEnd.getFileLocWithOffset(1), ";"); } else { // we don't have any instance variables - insert super struct. endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); Result += " {\n struct "; @@ -2973,7 +3042,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, Result += "_IMPL "; Result += RCDecl->getNameAsString(); Result += "_IVARS;\n};\n"; - ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size()); + ReplaceText(LocStart, endBuf-startBuf, Result); } // Mark this struct as having been generated. if (!ObjCSynthesizedStructs.insert(CDecl)) @@ -3805,7 +3874,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, // Create local declarations to avoid rewriting all closure decl ref exprs. // First, emit a declaration for all "by ref" decls. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { S += " "; std::string Name = (*I)->getNameAsString(); @@ -3816,7 +3885,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; } // Next, emit a declaration for all "by copy" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { S += " "; std::string Name = (*I)->getNameAsString(); @@ -3861,7 +3930,7 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, S += (*I)->getNameAsString(); S += ", (void*)src->"; S += (*I)->getNameAsString(); - if (BlockByRefDecls.count((*I))) + if (BlockByRefDeclsPtrSet.count((*I))) S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; else S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; @@ -3877,7 +3946,7 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, E = ImportedBlockDecls.end(); I != E; ++I) { S += "_Block_object_dispose((void*)src->"; S += (*I)->getNameAsString(); - if (BlockByRefDecls.count((*I))) + if (BlockByRefDeclsPtrSet.count((*I))) S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; else S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; @@ -3901,7 +3970,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, if (BlockDeclRefs.size()) { // Output all "by copy" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { S += " "; std::string FieldName = (*I)->getNameAsString(); @@ -3927,7 +3996,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, S += FieldName + ";\n"; } // Output all "by ref" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { S += " "; std::string FieldName = (*I)->getNameAsString(); @@ -3966,7 +4035,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += " Desc = desc;\n"; // Initialize all "by copy" arguments. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { std::string Name = (*I)->getNameAsString(); Constructor += " "; @@ -3977,7 +4046,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += Name + ";\n"; } // Initialize all "by ref" arguments. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { std::string Name = (*I)->getNameAsString(); Constructor += " "; @@ -4047,23 +4116,25 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); - InsertText(FunLocStart, CI.c_str(), CI.size()); + InsertText(FunLocStart, CI); std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); - InsertText(FunLocStart, CF.c_str(), CF.size()); + InsertText(FunLocStart, CF); if (ImportedBlockDecls.size()) { std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); - InsertText(FunLocStart, HF.c_str(), HF.size()); + InsertText(FunLocStart, HF); } std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, ImportedBlockDecls.size() > 0); - InsertText(FunLocStart, BD.c_str(), BD.size()); + InsertText(FunLocStart, BD); BlockDeclRefs.clear(); BlockByRefDecls.clear(); + BlockByRefDeclsPtrSet.clear(); BlockByCopyDecls.clear(); + BlockByCopyDeclsPtrSet.clear(); BlockCallExprs.clear(); ImportedBlockDecls.clear(); } @@ -4078,17 +4149,23 @@ void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { SynthesizeBlockLiterals(FunLocStart, FuncName); } -void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { - //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n"); - //SourceLocation FunLocStart = MD->getLocStart(); - // FIXME: This hack works around a bug in Rewrite.InsertText(). - SourceLocation FunLocStart = MD->getLocStart().getFileLocWithOffset(-1); - std::string FuncName = MD->getSelector().getAsString(); +static void BuildUniqueMethodName(std::string &Name, + ObjCMethodDecl *MD) { + ObjCInterfaceDecl *IFace = MD->getClassInterface(); + Name = IFace->getNameAsCString(); + Name += "__" + MD->getSelector().getAsString(); // Convert colons to underscores. std::string::size_type loc = 0; - while ((loc = FuncName.find(":", loc)) != std::string::npos) - FuncName.replace(loc, 1, "_"); + while ((loc = Name.find(":", loc)) != std::string::npos) + Name.replace(loc, 1, "_"); +} +void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { + //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n"); + //SourceLocation FunLocStart = MD->getLocStart(); + SourceLocation FunLocStart = MD->getLocStart(); + std::string FuncName; + BuildUniqueMethodName(FuncName, MD); SynthesizeBlockLiterals(FunLocStart, FuncName.c_str()); } @@ -4304,11 +4381,9 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { std::string TypeAsString = "("; TypeAsString += QT.getAsString(); TypeAsString += ")"; - ReplaceText(LocStart, endBuf-startBuf+1, - TypeAsString.c_str(), TypeAsString.size()); + ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString); return; } - // advance the location to startArgList. const char *argPtr = startBuf; @@ -4317,7 +4392,7 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { case '^': // Replace the '^' with '*'. LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); - ReplaceText(LocStart, 1, "*", 1); + ReplaceText(LocStart, 1, "*"); break; } } @@ -4346,7 +4421,7 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { case '^': // Replace the '^' with '*'. DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); - ReplaceText(DeclLoc, 1, "*", 1); + ReplaceText(DeclLoc, 1, "*"); break; case '(': parenCount++; @@ -4427,7 +4502,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { if (*startBuf == '^') { // Replace the '^' with '*', computing a negative offset. DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf); - ReplaceText(DeclLoc, 1, "*", 1); + ReplaceText(DeclLoc, 1, "*"); } if (PointerTypeTakesAnyBlockArguments(DeclT)) { // Replace the '^' with '*' for arguments. @@ -4438,7 +4513,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { while (argListBegin < argListEnd) { if (*argListBegin == '^') { SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf); - ReplaceText(CaretLoc, 1, "*", 1); + ReplaceText(CaretLoc, 1, "*"); } argListBegin++; } @@ -4563,7 +4638,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); FunLocStart = CurMethodDef->getLocStart(); } - InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size()); + InsertText(FunLocStart, ByrefType); if (Ty.isObjCGCWeak()) { flag |= BLOCK_FIELD_IS_WEAK; isa = 1; @@ -4579,7 +4654,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { flag |= BLOCK_FIELD_IS_OBJECT; std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag); if (!HF.empty()) - InsertText(FunLocStart, HF.c_str(), HF.size()); + InsertText(FunLocStart, HF); } // struct __Block_byref_ND ND = @@ -4592,10 +4667,12 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { Name = ND->getNameAsString(); ByrefType.clear(); RewriteByRefString(ByrefType, Name, ND); + std::string ForwardingCastType("("); + ForwardingCastType += ByrefType + " *)"; if (!hasInit) { ByrefType += " " + Name + " = {(void*)"; ByrefType += utostr(isa); - ByrefType += ", &" + Name + ", "; + ByrefType += "," + ForwardingCastType + "&" + Name + ", "; ByrefType += utostr(flags); ByrefType += ", "; ByrefType += "sizeof("; @@ -4608,8 +4685,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType += utostr(flag); } ByrefType += "};\n"; - ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), - ByrefType.c_str(), ByrefType.size()); + ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), ByrefType); } else { SourceLocation startLoc; @@ -4624,7 +4700,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType += " " + Name; ByrefType += " = {(void*)"; ByrefType += utostr(isa); - ByrefType += ", &" + Name + ", "; + ByrefType += "," + ForwardingCastType + "&" + Name + ", "; ByrefType += utostr(flags); ByrefType += ", "; ByrefType += "sizeof("; @@ -4637,8 +4713,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType += utostr(flag); ByrefType += ", "; } - ReplaceText(DeclLoc, endBuf-startBuf, - ByrefType.c_str(), ByrefType.size()); + ReplaceText(DeclLoc, endBuf-startBuf, ByrefType); // Complete the newly synthesized compound expression by inserting a right // curly brace before the end of the declaration. @@ -4654,7 +4729,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf); - InsertText(semiLoc, "}", 1); + InsertText(semiLoc, "}"); } return; } @@ -4665,12 +4740,19 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { if (BlockDeclRefs.size()) { // Unique all "by copy" declarations. for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (!BlockDeclRefs[i]->isByRef()) - BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl()); + if (!BlockDeclRefs[i]->isByRef()) { + if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { + BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); + BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl()); + } + } // Unique all "by ref" declarations. for (unsigned i = 0; i < BlockDeclRefs.size(); i++) if (BlockDeclRefs[i]->isByRef()) { - BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl()); + if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { + BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); + BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl()); + } } // Find any imported blocks...they will need special attention. for (unsigned i = 0; i < BlockDeclRefs.size(); i++) @@ -4699,13 +4781,9 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { if (CurFunctionDef) FuncName = CurFunctionDef->getNameAsString(); - else if (CurMethodDef) { - FuncName = CurMethodDef->getSelector().getAsString(); - // Convert colons to underscores. - std::string::size_type loc = 0; - while ((loc = FuncName.find(":", loc)) != std::string::npos) - FuncName.replace(loc, 1, "_"); - } else if (GlobalVarDecl) + else if (CurMethodDef) + BuildUniqueMethodName(FuncName, CurMethodDef); + else if (GlobalVarDecl) FuncName = std::string(GlobalVarDecl->getNameAsString()); std::string BlockNumber = utostr(Blocks.size()-1); @@ -4752,7 +4830,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { if (BlockDeclRefs.size()) { Expr *Exp; // Output all "by copy" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { if (isObjCType((*I)->getType())) { // FIXME: Conform to ABI ([[obj retain] autorelease]). @@ -4770,13 +4848,25 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { InitExprs.push_back(Exp); } // Output all "by ref" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { + ValueDecl *ND = (*I); + std::string Name(ND->getNameAsString()); + std::string RecName; + RewriteByRefString(RecName, Name, ND); + IdentifierInfo *II = &Context->Idents.get(RecName.c_str() + + sizeof("struct")); + RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl, + SourceLocation(), II); + assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); + QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); + FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, Context->getPointerType(Exp->getType()), SourceLocation()); + Exp = NoTypeInfoCStyleCastExpr(Context, castT, CastExpr::CK_Unknown, Exp); InitExprs.push_back(Exp); } } @@ -4798,7 +4888,9 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { NewRep); BlockDeclRefs.clear(); BlockByRefDecls.clear(); + BlockByRefDeclsPtrSet.clear(); BlockByCopyDecls.clear(); + BlockByCopyDeclsPtrSet.clear(); ImportedBlockDecls.clear(); return NewRep; } @@ -4843,7 +4935,21 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; ++CI) if (*CI) { - Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI); + Stmt *newStmt; + Stmt *S = (*CI); + if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) { + Expr *OldBase = IvarRefExpr->getBase(); + bool replaced = false; + newStmt = RewriteObjCNestedIvarRefExpr(S, replaced); + if (replaced) { + if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(newStmt)) + ReplaceStmt(OldBase, IRE->getBase()); + else + ReplaceStmt(S, newStmt); + } + } + else + newStmt = RewriteFunctionBodyOrGlobalInitializer(S); if (newStmt) *CI = newStmt; } @@ -4865,9 +4971,6 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S)) return RewriteAtEncode(AtEncode); - if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) - return RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin()); - if (ObjCPropertyRefExpr *PropRefExpr = dyn_cast<ObjCPropertyRefExpr>(S)) { BinaryOperator *BinOp = PropSetters[PropRefExpr]; if (BinOp) { @@ -4995,7 +5098,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { RewriteBlockPointerDecl(ND); else if (ND->getType()->isFunctionPointerType()) CheckFunctionPointerDecl(ND->getType(), ND); - if (VarDecl *VD = dyn_cast<VarDecl>(SD)) + if (VarDecl *VD = dyn_cast<VarDecl>(SD)) { if (VD->hasAttr<BlocksAttr>()) { static unsigned uniqueByrefDeclCount = 0; assert(!BlockByRefDeclNo.count(ND) && @@ -5003,6 +5106,9 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { BlockByRefDeclNo[ND] = uniqueByrefDeclCount++; RewriteByRefVar(VD); } + else + RewriteTypeOfDecl(VD); + } } if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { if (isTopLevelBlockPointerType(TD->getUnderlyingType())) @@ -5191,11 +5297,6 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { } void RewriteObjC::HandleTranslationUnit(ASTContext &C) { - // Get the top-level buffer that this corresponds to. - - // Rewrite tabs if we care. - //RewriteTabs(); - if (Diags.hasErrorOccurred()) return; @@ -5207,8 +5308,7 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) { E = ProtocolExprDecls.end(); I != E; ++I) RewriteObjCProtocolMetaData(*I, "", "", Preamble); - InsertText(SM->getLocForStartOfFile(MainFileID), - Preamble.c_str(), Preamble.size(), false); + InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false); if (ClassImplementation.size() || CategoryImplementation.size()) RewriteImplementations(); @@ -5219,7 +5319,7 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) { //printf("Changed:\n"); *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); } else { - fprintf(stderr, "No changes\n"); + llvm::errs() << "No changes\n"; } if (ClassImplementation.size() || CategoryImplementation.size() || diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 83b4542caa25..9ec5ffe1c353 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -104,11 +104,6 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, if (StartColNo) --StartColNo; // Zero base the col #. } - // Pick the first non-whitespace column. - while (StartColNo < SourceLine.size() && - (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) - ++StartColNo; - // Compute the column number of the end. unsigned EndColNo = CaretLine.size(); if (EndLineNo == LineNo) { @@ -123,16 +118,25 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, } } + assert(StartColNo <= EndColNo && "Invalid range!"); + + // Pick the first non-whitespace column. + while (StartColNo < SourceLine.size() && + (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) + ++StartColNo; + // Pick the last non-whitespace column. - if (EndColNo <= SourceLine.size()) - while (EndColNo-1 && - (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) - --EndColNo; - else + if (EndColNo > SourceLine.size()) EndColNo = SourceLine.size(); + while (EndColNo-1 && + (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) + --EndColNo; + + // If the start/end passed each other, then we are trying to highlight a range + // that just exists in whitespace, which must be some sort of other bug. + assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); // Fill the range with ~'s. - assert(StartColNo <= EndColNo && "Invalid range!"); for (unsigned i = StartColNo; i < EndColNo; ++i) CaretLine[i] = '~'; } diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index e27060295a81..b59c7e824bf1 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -462,7 +462,7 @@ _mm_cvtss_f32(__m128 a) } static inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_loadh_pi(__m128 a, __m64 const *p) +_mm_loadh_pi(__m128 a, const __m64 *p) { __m128 b; b[0] = *(float*)p; @@ -471,7 +471,7 @@ _mm_loadh_pi(__m128 a, __m64 const *p) } static inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_loadl_pi(__m128 a, __m64 const *p) +_mm_loadl_pi(__m128 a, const __m64 *p) { __m128 b; b[0] = *(float*)p; @@ -480,13 +480,13 @@ _mm_loadl_pi(__m128 a, __m64 const *p) } static inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_load_ss(float *p) +_mm_load_ss(const float *p) { return (__m128){ *p, 0, 0, 0 }; } static inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_load1_ps(float *p) +_mm_load1_ps(const float *p) { return (__m128){ *p, *p, *p, *p }; } @@ -494,19 +494,19 @@ _mm_load1_ps(float *p) #define _mm_load_ps1(p) _mm_load1_ps(p) static inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_load_ps(float *p) +_mm_load_ps(const float *p) { return *(__m128*)p; } static inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_loadu_ps(float *p) +_mm_loadu_ps(const float *p) { return __builtin_ia32_loadups(p); } static inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_loadr_ps(float *p) +_mm_loadr_ps(const float *p) { __m128 a = _mm_load_ps(p); return __builtin_shufflevector(a, a, 3, 2, 1, 0); @@ -895,7 +895,7 @@ do { \ (row0) = _mm_movelh_ps(tmp0, tmp2); \ (row1) = _mm_movehl_ps(tmp2, tmp0); \ (row2) = _mm_movelh_ps(tmp1, tmp3); \ - (row3) = _mm_movelh_ps(tmp3, tmp1); \ + (row3) = _mm_movehl_ps(tmp3, tmp1); \ } while (0) /* Ugly hack for backwards-compatibility (compatible with gcc) */ diff --git a/lib/Index/Makefile b/lib/Index/Makefile index 7dee87f3b6bb..9d33a2d175e3 100644 --- a/lib/Index/Makefile +++ b/lib/Index/Makefile @@ -16,7 +16,6 @@ include $(LEVEL)/Makefile.config LIBRARYNAME := clangIndex BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti ifeq ($(ARCH),PowerPC) CXXFLAGS += -maltivec diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index afd1ba885167..3207062ccadd 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -985,10 +985,11 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { if (CurPtr == BufferEnd+1) { --CurPtr; break; } } while (C != '\n' && C != '\r'); - // Found but did not consume the newline. - if (PP && PP->HandleComment(Result, - SourceRange(getSourceLocation(BufferPtr), - getSourceLocation(CurPtr)))) { + // Found but did not consume the newline. Notify comment handlers about the + // comment unless we're in a #if 0 block. + if (PP && !isLexingRawMode() && + PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr), + getSourceLocation(CurPtr)))) { BufferPtr = CurPtr; return true; // A token has to be returned. } @@ -1235,9 +1236,10 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { C = *CurPtr++; } - if (PP && PP->HandleComment(Result, - SourceRange(getSourceLocation(BufferPtr), - getSourceLocation(CurPtr)))) { + // Notify comment handlers about the comment unless we're in a #if 0 block. + if (PP && !isLexingRawMode() && + PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr), + getSourceLocation(CurPtr)))) { BufferPtr = CurPtr; return true; // A token has to be returned. } diff --git a/lib/Lex/Makefile b/lib/Lex/Makefile index a2437da812bd..509077017c2d 100644 --- a/lib/Lex/Makefile +++ b/lib/Lex/Makefile @@ -16,7 +16,6 @@ include $(LEVEL)/Makefile.config LIBRARYNAME := clangLex BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti ifeq ($(ARCH),PowerPC) CXXFLAGS += -maltivec diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp index 7c3780ffc0ac..6aeb6fa3a2f7 100644 --- a/lib/Lex/PPCaching.cpp +++ b/lib/Lex/PPCaching.cpp @@ -91,7 +91,7 @@ const Token &Preprocessor::PeekAhead(unsigned N) { void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) { assert(Tok.isAnnotation() && "Expected annotation token"); assert(CachedLexPos != 0 && "Expected to have some cached tokens"); - assert(CachedTokens[CachedLexPos-1].getLocation() == Tok.getAnnotationEndLoc() + assert(CachedTokens[CachedLexPos-1].getLastLoc() == Tok.getAnnotationEndLoc() && "The annotation should be until the most recent cached token"); // Start from the end of the cached tokens list and look for the token diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index b0e784bcd96a..4803c5ab85d5 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -1514,18 +1514,21 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, // Check to see if this is the last token on the #if[n]def line. CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef"); + IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); + MacroInfo *MI = getMacroInfo(MII); + if (CurPPLexer->getConditionalStackDepth() == 0) { - // If the start of a top-level #ifdef, inform MIOpt. - if (!ReadAnyTokensBeforeDirective) { + // If the start of a top-level #ifdef and if the macro is not defined, + // inform MIOpt that this might be the start of a proper include guard. + // Otherwise it is some other form of unknown conditional which we can't + // handle. + if (!ReadAnyTokensBeforeDirective && MI == 0) { assert(isIfndef && "#ifdef shouldn't reach here"); - CurPPLexer->MIOpt.EnterTopLevelIFNDEF(MacroNameTok.getIdentifierInfo()); + CurPPLexer->MIOpt.EnterTopLevelIFNDEF(MII); } else CurPPLexer->MIOpt.EnterTopLevelConditional(); } - IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); - MacroInfo *MI = getMacroInfo(MII); - // If there is a macro, process it. if (MI) // Mark it used. MI->setIsUsed(true); @@ -1558,7 +1561,7 @@ void Preprocessor::HandleIfDirective(Token &IfToken, // If this condition is equivalent to #ifndef X, and if this is the first // directive seen, handle it for the multiple-include optimization. if (CurPPLexer->getConditionalStackDepth() == 0) { - if (!ReadAnyTokensBeforeDirective && IfNDefMacro) + if (!ReadAnyTokensBeforeDirective && IfNDefMacro && ConditionalTrue) CurPPLexer->MIOpt.EnterTopLevelIFNDEF(IfNDefMacro); else CurPPLexer->MIOpt.EnterTopLevelConditional(); diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 13aeb88b1db0..b97ab2485d3d 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Lex/LexDiagnostic.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/raw_ostream.h" #include <cstdio> #include <ctime> using namespace clang; @@ -152,7 +153,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, MacroInfo *MI) { if (Callbacks) Callbacks->MacroExpands(Identifier, MI); - // If this is a macro exapnsion in the "#if !defined(x)" line for the file, + // If this is a macro expansion in the "#if !defined(x)" line for the file, // then the macro could expand to different things in other contexts, we need // to disable the optimization in this case. if (CurPPLexer) CurPPLexer->MIOpt.ExpandedMacro(); @@ -627,7 +628,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { ++NumBuiltinMacroExpanded; - char TmpBuffer[100]; + llvm::SmallString<128> TmpBuffer; + llvm::raw_svector_ostream OS(TmpBuffer); // Set up the return result. Tok.setIdentifierInfo(0); @@ -652,9 +654,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc); // __LINE__ expands to a simple numeric value. - sprintf(TmpBuffer, "%u", PLoc.getLine()); + OS << PLoc.getLine(); Tok.setKind(tok::numeric_constant); - CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) { // C99 6.10.8: "__FILE__: The presumed name of the current source file (a // character string literal)". This can be affected by #line. @@ -671,10 +672,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } // Escape this filename. Turn '\' -> '\\' '"' -> '\"' - std::string FN = PLoc.getFilename(); - FN = '"' + Lexer::Stringify(FN) + '"'; + llvm::SmallString<128> FN; + FN += PLoc.getFilename(); + Lexer::Stringify(FN); + OS << '"' << FN.str() << '"'; Tok.setKind(tok::string_literal); - CreateString(&FN[0], FN.size(), Tok, Tok.getLocation()); } else if (II == Ident__DATE__) { if (!DATELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); @@ -683,6 +685,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok.setLocation(SourceMgr.createInstantiationLoc(DATELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); + return; } else if (II == Ident__TIME__) { if (!TIMELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); @@ -691,6 +694,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok.setLocation(SourceMgr.createInstantiationLoc(TIMELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); + return; } else if (II == Ident__INCLUDE_LEVEL__) { // Compute the presumed include depth of this token. This can be affected // by GNU line markers. @@ -702,9 +706,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); // __INCLUDE_LEVEL__ expands to a simple numeric value. - sprintf(TmpBuffer, "%u", Depth); + OS << Depth; Tok.setKind(tok::numeric_constant); - CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); } else if (II == Ident__TIMESTAMP__) { // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. @@ -725,17 +728,13 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } else { Result = "??? ??? ?? ??:??:?? ????\n"; } - TmpBuffer[0] = '"'; - unsigned Len = strlen(Result); - memcpy(TmpBuffer+1, Result, Len-1); // Copy string without the newline. - TmpBuffer[Len] = '"'; + // Surround the string with " and strip the trailing newline. + OS << '"' << llvm::StringRef(Result, strlen(Result)-1) << '"'; Tok.setKind(tok::string_literal); - CreateString(TmpBuffer, Len+1, Tok, Tok.getLocation()); } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. - sprintf(TmpBuffer, "%u", CounterValue++); + OS << CounterValue++; Tok.setKind(tok::numeric_constant); - CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); } else if (II == Ident__has_feature || II == Ident__has_builtin) { // The argument to these two builtins should be a parenthesized identifier. @@ -770,9 +769,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Value = HasFeature(*this, FeatureII); } - sprintf(TmpBuffer, "%d", (int)Value); + OS << (int)Value; Tok.setKind(tok::numeric_constant); - CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); } else if (II == Ident__has_include || II == Ident__has_include_next) { // The argument to these two builtins should be a parenthesized @@ -784,10 +782,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { IsValid = EvaluateHasInclude(Value, Tok, II, *this); else IsValid = EvaluateHasIncludeNext(Value, Tok, II, *this); - sprintf(TmpBuffer, "%d", (int)Value); + OS << (int)Value; Tok.setKind(tok::numeric_constant); - CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); } else { assert(0 && "Unknown identifier!"); } + CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation()); } diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 5689baaac652..df0e702ab447 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -424,7 +424,7 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart, // advanced by 3 should return the location of b, not of \\. One compounding // detail of this is that the escape may be made by a trigraph. if (!Lexer::isObviouslySimpleCharacter(*TokPtr)) - PhysOffset = Lexer::SkipEscapedNewLines(TokPtr)-TokPtr; + PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr; return TokStart.getFileLocWithOffset(PhysOffset); } diff --git a/lib/Makefile b/lib/Makefile index d499ee555a38..538bf4394071 100755 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ LEVEL = ../../.. PARALLEL_DIRS = Headers Runtime Basic Lex Parse AST Sema CodeGen Analysis \ - Rewrite Frontend Index Driver + Checker Rewrite Frontend Index Driver include $(LEVEL)/Makefile.common diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 9e5f5a2ac098..4a699e7ad5e5 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -253,6 +253,11 @@ bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID); TypeSpecWidth = W; TSWLoc = Loc; + if (TypeAltiVecVector && ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::warn_vector_long_decl_spec_combination; + return true; + } return false; } @@ -289,6 +294,38 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, TypeRep = Rep; TSTLoc = Loc; TypeSpecOwned = Owned; + if (TypeAltiVecVector && (TypeSpecType == TST_double)) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_vector_double_decl_spec_combination; + return true; + } + return false; +} + +bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID) { + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_vector_decl_spec_combination; + return true; + } + TypeAltiVecVector = isAltiVecVector; + AltiVecLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID) { + if (!TypeAltiVecVector || (TypeSpecType != TST_unspecified)) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_pixel_decl_spec_combination; + return true; + } + TypeSpecType = TST_int; + TypeSpecSign = TSS_unsigned; + TypeSpecWidth = TSW_short; + TypeAltiVecPixel = isAltiVecPixel; + TSTLoc = Loc; return false; } diff --git a/lib/Parse/Makefile b/lib/Parse/Makefile index 5d69029edc1a..de16e3ea665a 100644 --- a/lib/Parse/Makefile +++ b/lib/Parse/Makefile @@ -14,7 +14,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangParse BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b5ba8acafc8d..8aa69363beee 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -733,7 +733,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, if (TagName) { Diag(Loc, diag::err_use_of_tag_name_without_tag) - << Tok.getIdentifierInfo() << TagName + << Tok.getIdentifierInfo() << TagName << getLang().CPlusPlus << CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName); // Parse this as a tag as if the missing tag were present. @@ -1029,6 +1029,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier()) goto DoneWithDeclSpec; + // Check for need to substitute AltiVec keyword tokens. + if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) + break; + // It has to be available as a typedef too! TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), CurScope); @@ -1270,6 +1274,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, DiagID); break; + case tok::kw___vector: + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + break; + case tok::kw___pixel: + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); + break; // class-specifier: case tok::kw_class: @@ -1395,20 +1405,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, /// [OBJC] class-name objc-protocol-refs[opt] [TODO] /// [OBJC] typedef-name objc-protocol-refs[opt] [TODO] /// [C++0x] 'decltype' ( expression ) +/// [AltiVec] '__vector' bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, const char *&PrevSpec, unsigned &DiagID, - const ParsedTemplateInfo &TemplateInfo) { + const ParsedTemplateInfo &TemplateInfo, + bool SuppressDeclarations) { SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { case tok::identifier: // foo::bar + // Check for need to substitute AltiVec keyword tokens. + if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) + break; + // Fall through. case tok::kw_typename: // typename foo::bar // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - TemplateInfo); + TemplateInfo, SuppressDeclarations); // Otherwise, not a type specifier. return false; case tok::coloncolon: // ::foo::bar @@ -1420,7 +1436,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - TemplateInfo); + TemplateInfo, SuppressDeclarations); // Otherwise, not a type specifier. return false; @@ -1519,14 +1535,21 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, DiagID); break; - + case tok::kw___vector: + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + break; + case tok::kw___pixel: + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); + break; + // class-specifier: case tok::kw_class: case tok::kw_struct: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); ConsumeToken(); - ParseClassSpecifier(Kind, Loc, DS, TemplateInfo); + ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS_none, + SuppressDeclarations); return true; } @@ -1750,14 +1773,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ConsumeToken(); if (!Tok.isObjCAtKeyword(tok::objc_defs)) { Diag(Tok, diag::err_unexpected_at); - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, true); continue; } ConsumeToken(); ExpectAndConsume(tok::l_paren, diag::err_expected_lparen); if (!Tok.is(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, true); continue; } llvm::SmallVector<DeclPtrTy, 16> Fields; @@ -1771,26 +1794,28 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, if (Tok.is(tok::semi)) { ConsumeToken(); } else if (Tok.is(tok::r_brace)) { - Diag(Tok, diag::ext_expected_semi_decl_list); + ExpectAndConsume(tok::semi, diag::ext_expected_semi_decl_list); break; } else { - Diag(Tok, diag::err_expected_semi_decl_list); - // Skip to end of block or statement + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); + // Skip to end of block or statement to avoid ext-warning on extra ';'. SkipUntil(tok::r_brace, true, true); + // If we stopped at a ';', eat it. + if (Tok.is(tok::semi)) ConsumeToken(); } } SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - AttributeList *AttrList = 0; + llvm::OwningPtr<AttributeList> AttrList; // If attributes exist after struct contents, parse them. if (Tok.is(tok::kw___attribute)) - AttrList = ParseGNUAttributes(); + AttrList.reset(ParseGNUAttributes()); Actions.ActOnFields(CurScope, RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(), LBraceLoc, RBraceLoc, - AttrList); + AttrList.get()); StructScope.Exit(); Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc); } @@ -1817,10 +1842,10 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ConsumeToken(); } - AttributeList *Attr = 0; + llvm::OwningPtr<AttributeList> Attr; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) - Attr = ParseGNUAttributes(); + Attr.reset(ParseGNUAttributes()); CXXScopeSpec SS; if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) { @@ -1870,7 +1895,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, bool Owned = false; bool IsDependent = false; DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK, - StartLoc, SS, Name, NameLoc, Attr, AS, + StartLoc, SS, Name, NameLoc, Attr.get(), + AS, Action::MultiTemplateParamsArg(Actions), Owned, IsDependent); assert(!IsDependent && "didn't expect dependent enum"); @@ -1878,10 +1904,12 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); - // TODO: semantic analysis on the declspec for enums. + // FIXME: The DeclSpec should keep the locations of both the keyword and the + // name (if there is one). + SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; const char *PrevSpec = 0; unsigned DiagID; - if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, DiagID, + if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID, TagDecl.getAs<void>(), Owned)) Diag(StartLoc, DiagID) << PrevSpec; } @@ -1948,14 +1976,14 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { // Eat the }. SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - AttributeList *Attr = 0; + llvm::OwningPtr<AttributeList> Attr; // If attributes exist after the identifier list, parse them. if (Tok.is(tok::kw___attribute)) - Attr = ParseGNUAttributes(); // FIXME: where do they do? + Attr.reset(ParseGNUAttributes()); // FIXME: where do they do? Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, EnumConstantDecls.data(), EnumConstantDecls.size(), - CurScope, Attr); + CurScope, Attr.get()); EnumScope.Exit(); Actions.ActOnTagFinishDefinition(CurScope, EnumDecl, RBraceLoc); @@ -1981,6 +2009,9 @@ bool Parser::isTypeSpecifierQualifier() { default: return false; case tok::identifier: // foo::bar + if (TryAltiVecVectorToken()) + return true; + // Fall through. case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. @@ -2026,6 +2057,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: + case tok::kw___vector: // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: @@ -2066,7 +2098,9 @@ bool Parser::isDeclarationSpecifier() { // Unfortunate hack to support "Class.factoryMethod" notation. if (getLang().ObjC1 && NextToken().is(tok::period)) return false; - // Fall through + if (TryAltiVecVectorToken()) + return true; + // Fall through. case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just @@ -2117,6 +2151,7 @@ bool Parser::isDeclarationSpecifier() { case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: + case tok::kw___vector: // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: @@ -2608,10 +2643,10 @@ void Parser::ParseParenDeclarator(Declarator &D) { // In either case, we need to eat any attributes to be able to determine what // sort of paren this is. // - AttributeList *AttrList = 0; + llvm::OwningPtr<AttributeList> AttrList; bool RequiresArg = false; if (Tok.is(tok::kw___attribute)) { - AttrList = ParseGNUAttributes(); + AttrList.reset(ParseGNUAttributes()); // We require that the argument list (if this is a non-grouping paren) be // present even if the attribute list was empty. @@ -2621,7 +2656,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64)) { - AttrList = ParseMicrosoftTypeAttributes(AttrList); + AttrList.reset(ParseMicrosoftTypeAttributes(AttrList.take())); } // If we haven't past the identifier yet (or where the identifier would be @@ -2652,7 +2687,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { bool hadGroupingParens = D.hasGroupingParens(); D.setGroupingParens(true); if (AttrList) - D.AddAttributes(AttrList, SourceLocation()); + D.AddAttributes(AttrList.take(), SourceLocation()); ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. @@ -2669,7 +2704,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // ParseFunctionDeclarator to handle of argument list. D.SetIdentifier(0, Tok.getLocation()); - ParseFunctionDeclarator(StartLoc, D, AttrList, RequiresArg); + ParseFunctionDeclarator(StartLoc, D, AttrList.take(), RequiresArg); } /// ParseFunctionDeclarator - We are after the identifier and have parsed the @@ -2762,7 +2797,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Alternatively, this parameter list may be an identifier list form for a // K&R-style function: void foo(a,b,c) - if (!getLang().CPlusPlus && Tok.is(tok::identifier)) { + if (!getLang().CPlusPlus && Tok.is(tok::identifier) + && !TryAltiVecVectorToken()) { if (!TryAnnotateTypeOrScopeToken()) { // K&R identifier lists can't have typedefs as identifiers, per // C99 6.7.5.3p11. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index efaf8ee3270e..51ee6a443488 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -64,12 +64,12 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, } // Read label attributes, if present. - Action::AttrTy *AttrList = 0; + llvm::OwningPtr<AttributeList> AttrList; if (Tok.is(tok::kw___attribute)) { attrTok = Tok; // FIXME: save these somewhere. - AttrList = ParseGNUAttributes(); + AttrList.reset(ParseGNUAttributes()); } if (Tok.is(tok::equal)) { @@ -91,7 +91,8 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, ParseScope NamespaceScope(this, Scope::DeclScope); DeclPtrTy NamespcDecl = - Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace); + Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace, + AttrList.get()); PrettyStackTraceActionsDecl CrashInfo(NamespcDecl, NamespaceLoc, Actions, PP.getSourceManager(), @@ -191,6 +192,8 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, SourceLocation()); } + DS.abort(); + if (Attr.HasAttr) Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) << Attr.Range; @@ -325,8 +328,6 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, // Parse nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); - AttributeList *AttrList = 0; - // Check nested-name specifier. if (SS.isInvalid()) { SkipUntil(tok::semi); @@ -348,8 +349,9 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, } // Parse (optional) attributes (most likely GNU strong-using extension). + llvm::OwningPtr<AttributeList> AttrList; if (Tok.is(tok::kw___attribute)) - AttrList = ParseGNUAttributes(); + AttrList.reset(ParseGNUAttributes()); // Eat ';'. DeclEnd = Tok.getLocation(); @@ -358,7 +360,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, tok::semi); return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name, - AttrList, IsTypeName, TypenameLoc); + AttrList.get(), IsTypeName, TypenameLoc); } /// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion. @@ -547,7 +549,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which /// until we reach the start of a definition or see a token that -/// cannot start a definition. +/// cannot start a definition. If SuppressDeclarations is true, we do know. /// /// class-specifier: [C++ class] /// class-head '{' member-specification[opt] '}' @@ -587,7 +589,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation StartLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, - AccessSpecifier AS) { + AccessSpecifier AS, bool SuppressDeclarations){ DeclSpec::TST TagType; if (TagTokKind == tok::kw_struct) TagType = DeclSpec::TST_struct; @@ -733,8 +735,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // have to be treated differently. If we have 'struct foo {...' or // 'struct foo :...' then this is a definition. Otherwise we have // something like 'struct foo xyz', a reference. + // However, in some contexts, things look like declarations but are just + // references, e.g. + // new struct s; + // or + // &T::operator struct s; + // For these, SuppressDeclarations is true. Action::TagUseKind TUK; - if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))) { + if (SuppressDeclarations) + TUK = Action::TUK_Reference; + else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))){ if (DS.isFriendSpecified()) { // C++ [class.friend]p2: // A class shall not be defined in a friend declaration. @@ -917,9 +927,62 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, const char *PrevSpec = 0; unsigned DiagID; - if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, DiagID, + // FIXME: The DeclSpec should keep the locations of both the keyword and the + // name (if there is one). + SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; + + if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID, Result, Owned)) Diag(StartLoc, DiagID) << PrevSpec; + + // At this point, we've successfully parsed a class-specifier in 'definition' + // form (e.g. "struct foo { int x; }". While we could just return here, we're + // going to look at what comes after it to improve error recovery. If an + // impossible token occurs next, we assume that the programmer forgot a ; at + // the end of the declaration and recover that way. + // + // This switch enumerates the valid "follow" set for definition. + if (TUK == Action::TUK_Definition) { + switch (Tok.getKind()) { + case tok::semi: // struct foo {...} ; + case tok::star: // struct foo {...} * P; + case tok::amp: // struct foo {...} & R = ... + case tok::identifier: // struct foo {...} V ; + case tok::r_paren: //(struct foo {...} ) {4} + case tok::annot_cxxscope: // struct foo {...} a:: b; + case tok::annot_typename: // struct foo {...} a ::b; + case tok::annot_template_id: // struct foo {...} a<int> ::b; + case tok::l_paren: // struct foo {...} ( x); + case tok::comma: // __builtin_offsetof(struct foo{...} , + // Storage-class specifiers + case tok::kw_static: // struct foo {...} static x; + case tok::kw_extern: // struct foo {...} extern x; + case tok::kw_typedef: // struct foo {...} typedef x; + case tok::kw_register: // struct foo {...} register x; + case tok::kw_auto: // struct foo {...} auto x; + // Type qualifiers + case tok::kw_const: // struct foo {...} const x; + case tok::kw_volatile: // struct foo {...} volatile x; + case tok::kw_restrict: // struct foo {...} restrict x; + case tok::kw_inline: // struct foo {...} inline foo() {}; + break; + + case tok::r_brace: // struct bar { struct foo {...} } + // Missing ';' at end of struct is accepted as an extension in C mode. + if (!getLang().CPlusPlus) break; + // FALL THROUGH. + default: + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + TagType == DeclSpec::TST_class ? "class" + : TagType == DeclSpec::TST_struct? "struct" : "union"); + // Push this token back into the preprocessor and change our current token + // to ';' so that the rest of the code recovers as though there were an + // ';' after the definition. + PP.EnterToken(Tok); + Tok.setKind(tok::semi); + break; + } + } } /// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived]. @@ -1164,7 +1227,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return ParseCXXClassMemberDeclaration(AS, TemplateInfo); } - // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it + // is a bitfield. ColonProtectionRAIIObject X(*this); CXX0XAttributeList AttrList; @@ -1185,8 +1249,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::kw_namespace)) { Diag(UsingLoc, diag::err_using_namespace_in_class); SkipUntil(tok::semi, true, true); - } - else { + } else { SourceLocation DeclEnd; // Otherwise, it must be using-declaration. ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS); @@ -1367,19 +1430,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseDeclarator(DeclaratorInfo); } - if (Tok.is(tok::semi)) { - ConsumeToken(); - Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(), - DeclsInGroup.size()); + if (ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { + // Skip to end of block or statement. + SkipUntil(tok::r_brace, true, true); + // If we stopped at a ';', eat it. + if (Tok.is(tok::semi)) ConsumeToken(); return; } - Diag(Tok, diag::err_expected_semi_decl_list); - // Skip to end of block or statement - SkipUntil(tok::r_brace, true, true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return; + Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(), + DeclsInGroup.size()); } /// ParseCXXMemberSpecification - Parse the class definition. @@ -1489,10 +1549,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - AttributeList *AttrList = 0; // If attributes exist after class contents, parse them. + llvm::OwningPtr<AttributeList> AttrList; if (Tok.is(tok::kw___attribute)) - AttrList = ParseGNUAttributes(); // FIXME: where should I put them? + AttrList.reset(ParseGNUAttributes()); // FIXME: where should I put them? Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl, LBraceLoc, RBraceLoc); @@ -1546,12 +1606,15 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { SourceLocation ColonLoc = ConsumeToken(); llvm::SmallVector<MemInitTy*, 4> MemInitializers; - + bool AnyErrors = false; + do { MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); if (!MemInit.isInvalid()) MemInitializers.push_back(MemInit.get()); - + else + AnyErrors = true; + if (Tok.is(tok::comma)) ConsumeToken(); else if (Tok.is(tok::l_brace)) @@ -1565,7 +1628,8 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { } while (true); Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, - MemInitializers.data(), MemInitializers.size()); + MemInitializers.data(), MemInitializers.size(), + AnyErrors); } /// ParseMemInitializer - Parse a C++ member initializer, which is diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 669575c4f030..c763c2c6f65f 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -22,6 +22,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" #include "clang/Basic/PrettyStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallVector.h" @@ -780,6 +781,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: + case tok::kw___vector: case tok::annot_typename: { if (!getLang().CPlusPlus) { Diag(Tok, diag::err_expected_expression); @@ -805,9 +807,44 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ParsePostfixExpressionSuffix(move(Res)); } - case tok::annot_cxxscope: // [C++] id-expression: qualified-id + case tok::annot_cxxscope: { // [C++] id-expression: qualified-id + Token Next = NextToken(); + if (Next.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()); + if (TemplateId->Kind == TNK_Type_template) { + // We have a qualified template-id that we know refers to a + // type, translate it into a type and continue parsing as a + // cast expression. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + AnnotateTemplateIdTokenAsType(&SS); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); + } + } + + // Parse as an id-expression. + Res = ParseCXXIdExpression(isAddressOfOperand); + return ParsePostfixExpressionSuffix(move(Res)); + } + + case tok::annot_template_id: { // [C++] template-id + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + if (TemplateId->Kind == TNK_Type_template) { + // We have a template-id that we know refers to a type, + // translate it into a type and continue parsing as a cast + // expression. + AnnotateTemplateIdTokenAsType(); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); + } + + // Fall through to treat the template-id as an id-expression. + } + case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id - case tok::annot_template_id: // [C++] template-id Res = ParseCXXIdExpression(isAddressOfOperand); return ParsePostfixExpressionSuffix(move(Res)); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index ca50ef400092..0dbe1ea83890 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -763,12 +763,15 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { bool isInvalid = 0; // Parse one or more of the type specifiers. - if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) { + if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + ParsedTemplateInfo(), /*SuppressDeclarations*/true)) { Diag(Tok, diag::err_operator_missing_type_specifier); return true; } - while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) ; + while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + ParsedTemplateInfo(), /*SuppressDeclarations*/true)) + {} return false; } diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index ae85aa3a8aef..d1c9be233fe0 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -515,7 +515,8 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl, DS.setSetterName(Tok.getIdentifierInfo()); ConsumeToken(); // consume method name - if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "", + if (ExpectAndConsume(tok::colon, + diag::err_expected_colon_after_setter_name, "", tok::r_paren)) return; } else { @@ -786,15 +787,15 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, llvm::SmallVector<Declarator, 8> CargNames; if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. - AttributeList *MethodAttrs = 0; + llvm::OwningPtr<AttributeList> MethodAttrs; if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs = ParseGNUAttributes(); + MethodAttrs.reset(ParseGNUAttributes()); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); DeclPtrTy Result = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, - 0, CargNames, MethodAttrs, + 0, CargNames, MethodAttrs.get(), MethodImplKind); PD.complete(Result); return Result; @@ -862,9 +863,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // FIXME: Add support for optional parmameter list... // If attributes exist after the method, parse them. - AttributeList *MethodAttrs = 0; + llvm::OwningPtr<AttributeList> MethodAttrs; if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs = ParseGNUAttributes(); + MethodAttrs.reset(ParseGNUAttributes()); if (KeyIdents.size() == 0) return DeclPtrTy(); @@ -873,9 +874,16 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, DeclPtrTy Result = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, - &ArgInfos[0], CargNames, MethodAttrs, + &ArgInfos[0], CargNames, + MethodAttrs.get(), MethodImplKind, isVariadic); PD.complete(Result); + + // Delete referenced AttributeList objects. + for (llvm::SmallVectorImpl<Action::ObjCArgInfo>::iterator + I = ArgInfos.begin(), E = ArgInfos.end(); I != E; ++I) + delete I->ArgAttrs; + return Result; } @@ -1481,7 +1489,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { // Inform the actions module about the parameter declarator, so it // gets added to the current scope. + // FIXME. Probably can build a VarDecl and avoid setting DeclContext. FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl); + Actions.ActOnObjCCatchParam(FirstPart); } else ConsumeToken(); // consume '...' diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 21e960aa8173..9fd145dc2676 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -81,6 +81,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { CXX0XAttributeList Attr; if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) Attr = ParseCXX0XAttributes(); + llvm::OwningPtr<AttributeList> AttrList(Attr.AttrList); // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), @@ -102,13 +103,14 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { case tok::identifier: if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement - return ParseLabeledStatement(Attr.AttrList); + return ParseLabeledStatement(AttrList.take()); } // PASS THROUGH. default: { if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + AttrList.take(); //Passing 'Attr' to ParseDeclaration transfers ownership. DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd, Attr); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); @@ -135,43 +137,43 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } case tok::kw_case: // C99 6.8.1: labeled-statement - return ParseCaseStatement(Attr.AttrList); + return ParseCaseStatement(AttrList.take()); case tok::kw_default: // C99 6.8.1: labeled-statement - return ParseDefaultStatement(Attr.AttrList); + return ParseDefaultStatement(AttrList.take()); case tok::l_brace: // C99 6.8.2: compound-statement - return ParseCompoundStatement(Attr.AttrList); + return ParseCompoundStatement(AttrList.take()); case tok::semi: // C99 6.8.3p3: expression[opt] ';' return Actions.ActOnNullStmt(ConsumeToken()); case tok::kw_if: // C99 6.8.4.1: if-statement - return ParseIfStatement(Attr.AttrList); + return ParseIfStatement(AttrList.take()); case tok::kw_switch: // C99 6.8.4.2: switch-statement - return ParseSwitchStatement(Attr.AttrList); + return ParseSwitchStatement(AttrList.take()); case tok::kw_while: // C99 6.8.5.1: while-statement - return ParseWhileStatement(Attr.AttrList); + return ParseWhileStatement(AttrList.take()); case tok::kw_do: // C99 6.8.5.2: do-statement - Res = ParseDoStatement(Attr.AttrList); + Res = ParseDoStatement(AttrList.take()); SemiError = "do/while"; break; case tok::kw_for: // C99 6.8.5.3: for-statement - return ParseForStatement(Attr.AttrList); + return ParseForStatement(AttrList.take()); case tok::kw_goto: // C99 6.8.6.1: goto-statement - Res = ParseGotoStatement(Attr.AttrList); + Res = ParseGotoStatement(AttrList.take()); SemiError = "goto"; break; case tok::kw_continue: // C99 6.8.6.2: continue-statement - Res = ParseContinueStatement(Attr.AttrList); + Res = ParseContinueStatement(AttrList.take()); SemiError = "continue"; break; case tok::kw_break: // C99 6.8.6.3: break-statement - Res = ParseBreakStatement(Attr.AttrList); + Res = ParseBreakStatement(AttrList.take()); SemiError = "break"; break; case tok::kw_return: // C99 6.8.6.4: return-statement - Res = ParseReturnStatement(Attr.AttrList); + Res = ParseReturnStatement(AttrList.take()); SemiError = "return"; break; @@ -187,7 +189,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } case tok::kw_try: // C++ 15: try-block - return ParseCXXTryBlock(Attr.AttrList); + return ParseCXXTryBlock(AttrList.take()); } // If we reached this code, the statement must end in a semicolon. @@ -215,6 +217,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); + llvm::OwningPtr<AttributeList> AttrList(Attr); Token IdentTok = Tok; // Save the whole token. ConsumeToken(); // eat the identifier. @@ -225,7 +228,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { // Read label attributes, if present. if (Tok.is(tok::kw___attribute)) - Attr = addAttributeLists(Attr, ParseGNUAttributes()); + AttrList.reset(addAttributeLists(AttrList.take(), ParseGNUAttributes())); OwningStmtResult SubStmt(ParseStatement()); @@ -233,6 +236,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); + // FIXME: use attributes? return Actions.ActOnLabelStmt(IdentTok.getLocation(), IdentTok.getIdentifierInfo(), ColonLoc, move(SubStmt)); @@ -246,6 +250,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { assert(Tok.is(tok::kw_case) && "Not a case stmt!"); // FIXME: Use attributes? + delete Attr; // It is very very common for code to contain many case statements recursively // nested, as in (but usually without indentation): @@ -371,6 +376,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { /// Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { //FIXME: Use attributes? + delete Attr; + assert(Tok.is(tok::kw_default) && "Not a default stmt!"); SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. @@ -427,6 +434,8 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr, bool isStmtExpr) { //FIXME: Use attributes? + delete Attr; + assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); // Enter a scope to hold everything within the compound stmt. Compound @@ -562,6 +571,8 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult, /// Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { // FIXME: Use attributes? + delete Attr; + assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. @@ -686,6 +697,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { /// [C++] 'switch' '(' condition ')' statement Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { // FIXME: Use attributes? + delete Attr; + assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. @@ -741,19 +754,19 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { // Read the body statement. OwningStmtResult Body(ParseStatement()); - // Pop the body scope if needed. + // Pop the scopes. InnerScope.Exit(); - - if (Body.isInvalid()) { - Body = Actions.ActOnNullStmt(Tok.getLocation()); - // FIXME: Remove the case statement list from the Switch statement. - } - SwitchScope.Exit(); - if (Cond.isInvalid() && !CondVar.get()) + if (Cond.isInvalid() && !CondVar.get()) { + Actions.ActOnSwitchBodyError(SwitchLoc, move(Switch), move(Body)); return StmtError(); + } + if (Body.isInvalid()) + // FIXME: Remove the case statement list from the Switch statement. + Body = Actions.ActOnNullStmt(Tok.getLocation()); + return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body)); } @@ -763,6 +776,8 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { /// [C++] 'while' '(' condition ')' statement Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) { // FIXME: Use attributes? + delete Attr; + assert(Tok.is(tok::kw_while) && "Not a while stmt!"); SourceLocation WhileLoc = Tok.getLocation(); ConsumeToken(); // eat the 'while'. @@ -836,6 +851,8 @@ Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) { /// Note: this lets the caller parse the end ';'. Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) { // FIXME: Use attributes? + delete Attr; + assert(Tok.is(tok::kw_do) && "Not a do stmt!"); SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. @@ -911,6 +928,8 @@ Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) { /// Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { // FIXME: Use attributes? + delete Attr; + assert(Tok.is(tok::kw_for) && "Not a for stmt!"); SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. @@ -1081,6 +1100,8 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { /// Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) { // FIXME: Use attributes? + delete Attr; + assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. @@ -1115,6 +1136,8 @@ Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) { /// Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) { // FIXME: Use attributes? + delete Attr; + SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. return Actions.ActOnContinueStmt(ContinueLoc, CurScope); } @@ -1127,6 +1150,8 @@ Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) { /// Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) { // FIXME: Use attributes? + delete Attr; + SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. return Actions.ActOnBreakStmt(BreakLoc, CurScope); } @@ -1136,6 +1161,8 @@ Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) { /// 'return' expression[opt] ';' Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) { // FIXME: Use attributes? + delete Attr; + assert(Tok.is(tok::kw_return) && "Not a return stmt!"); SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. @@ -1171,7 +1198,6 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && Tok.isNot(tok::eof)); } - llvm::SmallVector<std::string, 4> Names; Token t; t.setKind(tok::string_literal); t.setLiteralData("\"FIXME: not done\""); @@ -1181,7 +1207,7 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { ExprVector Constraints(Actions); ExprVector Exprs(Actions); ExprVector Clobbers(Actions); - return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, Names.data(), + return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, 0, move_arg(Constraints), move_arg(Exprs), move(AsmString), move_arg(Clobbers), Tok.getLocation(), true); @@ -1245,7 +1271,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { if (AsmString.isInvalid()) return StmtError(); - llvm::SmallVector<std::string, 4> Names; + llvm::SmallVector<IdentifierInfo *, 4> Names; ExprVector Constraints(Actions); ExprVector Exprs(Actions); ExprVector Clobbers(Actions); @@ -1336,9 +1362,9 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { /// // // FIXME: Avoid unnecessary std::string trashing. -bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, - llvm::SmallVectorImpl<ExprTy*> &Constraints, - llvm::SmallVectorImpl<ExprTy*> &Exprs) { +bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names, + llvm::SmallVectorImpl<ExprTy *> &Constraints, + llvm::SmallVectorImpl<ExprTy *> &Exprs) { // 'asm-operands' isn't present? if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) return false; @@ -1357,10 +1383,10 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, IdentifierInfo *II = Tok.getIdentifierInfo(); ConsumeToken(); - Names.push_back(II->getName()); + Names.push_back(II); MatchRHSPunctuation(tok::r_square, Loc); } else - Names.push_back(std::string()); + Names.push_back(0); OwningExprResult Constraint(ParseAsmStringLiteral()); if (Constraint.isInvalid()) { @@ -1448,6 +1474,8 @@ Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) { /// Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) { // FIXME: Add attributes? + delete Attr; + assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 797c1dfe3e6a..12f26bfcb94e 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -836,7 +836,7 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { Tok.setAnnotationValue(Type.isInvalid()? 0 : Type.get()); if (SS && SS->isNotEmpty()) // it was a C++ qualified type name. Tok.setLocation(SS->getBeginLoc()); - Tok.setAnnotationEndLoc(TemplateId->TemplateNameLoc); + // End location stays the same // Replace the template-id annotation token, and possible the scope-specifier // that precedes it, with the typename annotation token. diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 51c56706bb59..6251a2f36754 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -672,6 +672,11 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, Parser::TPResult Parser::isCXXDeclarationSpecifier() { switch (Tok.getKind()) { case tok::identifier: // foo::bar + // Check for need to substitute AltiVec __vector keyword + // for "vector" identifier. + if (TryAltiVecVectorToken()) + return TPResult::True(); + // Fall through. case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. @@ -750,6 +755,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___ptr64: case tok::kw___forceinline: return TPResult::True(); + + // AltiVec + case tok::kw___vector: + return TPResult::True(); case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed // We've already annotated a scope; try to annotate a type. diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f2bc303acd69..30899c5dddb5 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -346,6 +346,11 @@ void Parser::Initialize() { } Ident_super = &PP.getIdentifierTable().get("super"); + + if (getLang().AltiVec) { + Ident_vector = &PP.getIdentifierTable().get("vector"); + Ident_pixel = &PP.getIdentifierTable().get("pixel"); + } } /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the @@ -588,7 +593,6 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, if (Tok.is(tok::string_literal) && getLang().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { - DS.abort(); DeclPtrTy TheDecl = ParseLinkage(DS, Declarator::FileContext); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -738,11 +742,11 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { // Handle the full declarator list. while (1) { - Action::AttrTy *AttrList; // If attributes are present, parse them. + llvm::OwningPtr<AttributeList> AttrList; if (Tok.is(tok::kw___attribute)) // FIXME: attach attributes too. - AttrList = ParseGNUAttributes(); + AttrList.reset(ParseGNUAttributes()); // Ask the actions module to compute the type for this declarator. Action::DeclPtrTy Param = @@ -835,6 +839,16 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { assert(Tok.is(tok::kw_asm) && "Not an asm!"); SourceLocation Loc = ConsumeToken(); + if (Tok.is(tok::kw_volatile)) { + // Remove from the end of 'asm' to the end of 'volatile'. + SourceRange RemovalRange(PP.getLocForEndOfToken(Loc), + PP.getLocForEndOfToken(Tok.getLocation())); + + Diag(Tok, diag::warn_file_asm_volatile) + << CodeModificationHint::CreateRemoval(RemovalRange); + ConsumeToken(); + } + if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "asm"; return ExprError(); @@ -930,9 +944,10 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { return false; } + SourceLocation EndLoc = Tok.getLastLoc(); Tok.setKind(tok::annot_typename); Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get()); - Tok.setAnnotationEndLoc(Tok.getLocation()); + Tok.setAnnotationEndLoc(EndLoc); Tok.setLocation(TypenameLoc); PP.AnnotateCachedTokens(Tok); return true; diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile index 61fdf4006f86..a6d3f7725689 100644 --- a/lib/Rewrite/Makefile +++ b/lib/Rewrite/Makefile @@ -14,7 +14,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangRewrite BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index bff47519a743..b09526e097b6 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -14,8 +14,6 @@ #include "IdentifierResolver.h" #include "clang/Basic/LangOptions.h" -#include <list> -#include <vector> using namespace clang; @@ -27,14 +25,31 @@ using namespace clang; /// Allocates 'pools' (vectors of IdDeclInfos) to avoid allocating each /// individual IdDeclInfo to heap. class IdentifierResolver::IdDeclInfoMap { - static const unsigned int VECTOR_SIZE = 512; - // Holds vectors of IdDeclInfos that serve as 'pools'. - // New vectors are added when the current one is full. - std::list< std::vector<IdDeclInfo> > IDIVecs; + static const unsigned int POOL_SIZE = 512; + + /// We use our own linked-list implementation because it is sadly + /// impossible to add something to a pre-C++0x STL container without + /// a completely unnecessary copy. + struct IdDeclInfoPool { + IdDeclInfoPool(IdDeclInfoPool *Next) : Next(Next) {} + + IdDeclInfoPool *Next; + IdDeclInfo Pool[POOL_SIZE]; + }; + + IdDeclInfoPool *CurPool; unsigned int CurIndex; public: - IdDeclInfoMap() : CurIndex(VECTOR_SIZE) {} + IdDeclInfoMap() : CurPool(0), CurIndex(POOL_SIZE) {} + + ~IdDeclInfoMap() { + IdDeclInfoPool *Cur = CurPool; + while (IdDeclInfoPool *P = Cur) { + Cur = Cur->Next; + delete P; + } + } /// Returns the IdDeclInfo associated to the DeclarationName. /// It creates a new IdDeclInfo if one was not created before for this id. @@ -235,14 +250,11 @@ IdentifierResolver::IdDeclInfoMap::operator[](DeclarationName Name) { if (Ptr) return *toIdDeclInfo(Ptr); - if (CurIndex == VECTOR_SIZE) { - // Add a IdDeclInfo vector 'pool' - IDIVecs.push_back(std::vector<IdDeclInfo>()); - // Fill the vector - IDIVecs.back().resize(VECTOR_SIZE); + if (CurIndex == POOL_SIZE) { + CurPool = new IdDeclInfoPool(CurPool); CurIndex = 0; } - IdDeclInfo *IDI = &IDIVecs.back()[CurIndex]; + IdDeclInfo *IDI = &CurPool->Pool[CurIndex]; Name.setFETokenInfo(reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(IDI) | 0x1) ); diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index f4cea2e88a6d..6b2694591f52 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -224,6 +224,10 @@ public: return Ambiguity; } + const UnresolvedSetImpl &asUnresolvedSet() const { + return Decls; + } + iterator begin() const { return iterator(Decls.begin()); } iterator end() const { return iterator(Decls.end()); } @@ -499,7 +503,7 @@ private: if (isAmbiguous()) SemaRef.DiagnoseAmbiguousLookup(*this); else if (isClassLookup() && SemaRef.getLangOptions().AccessControl) - SemaRef.CheckAccess(*this); + SemaRef.CheckLookupAccess(*this); } void setAmbiguous(AmbiguityKind AK) { @@ -583,6 +587,44 @@ private: virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) = 0; }; + +/// \brief A class for storing results from argument-dependent lookup. +class ADLResult { +private: + /// A map from canonical decls to the 'most recent' decl. + llvm::DenseMap<NamedDecl*, NamedDecl*> Decls; + +public: + /// Adds a new ADL candidate to this map. + void insert(NamedDecl *D); + + /// Removes any data associated with a given decl. + void erase(NamedDecl *D) { + Decls.erase(cast<NamedDecl>(D->getCanonicalDecl())); + } + + class iterator { + typedef llvm::DenseMap<NamedDecl*,NamedDecl*>::iterator inner_iterator; + inner_iterator iter; + + friend class ADLResult; + iterator(const inner_iterator &iter) : iter(iter) {} + public: + iterator() {} + + iterator &operator++() { ++iter; return *this; } + iterator operator++(int) { return iterator(iter++); } + + NamedDecl *operator*() const { return iter->second; } + + bool operator==(const iterator &other) const { return iter == other.iter; } + bool operator!=(const iterator &other) const { return iter != other.iter; } + }; + + iterator begin() { return iterator(Decls.begin()); } + iterator end() { return iterator(Decls.end()); } +}; + } #endif diff --git a/lib/Sema/Makefile b/lib/Sema/Makefile index 0f4c7965dca2..158f1af213d4 100644 --- a/lib/Sema/Makefile +++ b/lib/Sema/Makefile @@ -15,7 +15,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangSema BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 171101bb96de..38c842eede57 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -15,260 +15,18 @@ #include "Sema.h" #include "TargetAttributesSema.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/APFloat.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" using namespace clang; - -/// Determines whether we should have an a.k.a. clause when -/// pretty-printing a type. There are three main criteria: -/// -/// 1) Some types provide very minimal sugar that doesn't impede the -/// user's understanding --- for example, elaborated type -/// specifiers. If this is all the sugar we see, we don't want an -/// a.k.a. clause. -/// 2) Some types are technically sugared but are much more familiar -/// when seen in their sugared form --- for example, va_list, -/// vector types, and the magic Objective C types. We don't -/// want to desugar these, even if we do produce an a.k.a. clause. -/// 3) Some types may have already been desugared previously in this diagnostic. -/// if this is the case, doing another "aka" would just be clutter. -/// -static bool ShouldAKA(ASTContext &Context, QualType QT, - const Diagnostic::ArgumentValue *PrevArgs, - unsigned NumPrevArgs, - QualType &DesugaredQT) { - QualType InputTy = QT; - - bool AKA = false; - QualifierCollector Qc; - - while (true) { - const Type *Ty = Qc.strip(QT); - - // Don't aka just because we saw an elaborated type... - if (isa<ElaboratedType>(Ty)) { - QT = cast<ElaboratedType>(Ty)->desugar(); - continue; - } - - // ...or a qualified name type... - if (isa<QualifiedNameType>(Ty)) { - QT = cast<QualifiedNameType>(Ty)->desugar(); - continue; - } - - // ...or a substituted template type parameter. - if (isa<SubstTemplateTypeParmType>(Ty)) { - QT = cast<SubstTemplateTypeParmType>(Ty)->desugar(); - continue; - } - - // Don't desugar template specializations. - if (isa<TemplateSpecializationType>(Ty)) - break; - - // Don't desugar magic Objective-C types. - if (QualType(Ty,0) == Context.getObjCIdType() || - QualType(Ty,0) == Context.getObjCClassType() || - QualType(Ty,0) == Context.getObjCSelType() || - QualType(Ty,0) == Context.getObjCProtoType()) - break; - - // Don't desugar va_list. - if (QualType(Ty,0) == Context.getBuiltinVaListType()) - break; - - // Otherwise, do a single-step desugar. - QualType Underlying; - bool IsSugar = false; - switch (Ty->getTypeClass()) { -#define ABSTRACT_TYPE(Class, Base) -#define TYPE(Class, Base) \ - case Type::Class: { \ - const Class##Type *CTy = cast<Class##Type>(Ty); \ - if (CTy->isSugared()) { \ - IsSugar = true; \ - Underlying = CTy->desugar(); \ - } \ - break; \ - } -#include "clang/AST/TypeNodes.def" - } - - // If it wasn't sugared, we're done. - if (!IsSugar) - break; - - // If the desugared type is a vector type, we don't want to expand - // it, it will turn into an attribute mess. People want their "vec4". - if (isa<VectorType>(Underlying)) - break; - - // Don't desugar through the primary typedef of an anonymous type. - if (isa<TagType>(Underlying) && isa<TypedefType>(QT)) - if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() == - cast<TypedefType>(QT)->getDecl()) - break; - - // Otherwise, we're tearing through something opaque; note that - // we'll eventually need an a.k.a. clause and keep going. - AKA = true; - QT = Underlying; - continue; - } - - // If we never tore through opaque sugar, don't print aka. - if (!AKA) return false; - - // If we did, check to see if we already desugared this type in this - // diagnostic. If so, don't do it again. - for (unsigned i = 0; i != NumPrevArgs; ++i) { - // TODO: Handle ak_declcontext case. - if (PrevArgs[i].first == Diagnostic::ak_qualtype) { - void *Ptr = (void*)PrevArgs[i].second; - QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); - if (PrevTy == InputTy) - return false; - } - } - - DesugaredQT = Qc.apply(QT); - return true; -} - -/// \brief Convert the given type to a string suitable for printing as part of -/// a diagnostic. -/// -/// \param Context the context in which the type was allocated -/// \param Ty the type to print -static std::string -ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, - const Diagnostic::ArgumentValue *PrevArgs, - unsigned NumPrevArgs) { - // FIXME: Playing with std::string is really slow. - std::string S = Ty.getAsString(Context.PrintingPolicy); - - // Consider producing an a.k.a. clause if removing all the direct - // sugar gives us something "significantly different". - - QualType DesugaredTy; - if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) { - S = "'"+S+"' (aka '"; - S += DesugaredTy.getAsString(Context.PrintingPolicy); - S += "')"; - return S; - } - - S = "'" + S + "'"; - return S; -} -/// ConvertQualTypeToStringFn - This function is used to pretty print the -/// specified QualType as a string in diagnostics. -static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, - const char *Modifier, unsigned ModLen, - const char *Argument, unsigned ArgLen, - const Diagnostic::ArgumentValue *PrevArgs, - unsigned NumPrevArgs, - llvm::SmallVectorImpl<char> &Output, - void *Cookie) { - ASTContext &Context = *static_cast<ASTContext*>(Cookie); - - std::string S; - bool NeedQuotes = true; - - switch (Kind) { - default: assert(0 && "unknown ArgumentKind"); - case Diagnostic::ak_qualtype: { - assert(ModLen == 0 && ArgLen == 0 && - "Invalid modifier for QualType argument"); - - QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); - S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs); - NeedQuotes = false; - break; - } - case Diagnostic::ak_declarationname: { - DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); - S = N.getAsString(); - - if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0) - S = '+' + S; - else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0) - S = '-' + S; - else - assert(ModLen == 0 && ArgLen == 0 && - "Invalid modifier for DeclarationName argument"); - break; - } - case Diagnostic::ak_nameddecl: { - bool Qualified; - if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) - Qualified = true; - else { - assert(ModLen == 0 && ArgLen == 0 && - "Invalid modifier for NamedDecl* argument"); - Qualified = false; - } - reinterpret_cast<NamedDecl*>(Val)-> - getNameForDiagnostic(S, Context.PrintingPolicy, Qualified); - break; - } - case Diagnostic::ak_nestednamespec: { - llvm::raw_string_ostream OS(S); - reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS, - Context.PrintingPolicy); - NeedQuotes = false; - break; - } - case Diagnostic::ak_declcontext: { - DeclContext *DC = reinterpret_cast<DeclContext *> (Val); - assert(DC && "Should never have a null declaration context"); - - if (DC->isTranslationUnit()) { - // FIXME: Get these strings from some localized place - if (Context.getLangOptions().CPlusPlus) - S = "the global namespace"; - else - S = "the global scope"; - } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { - S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type), - PrevArgs, NumPrevArgs); - } else { - // FIXME: Get these strings from some localized place - NamedDecl *ND = cast<NamedDecl>(DC); - if (isa<NamespaceDecl>(ND)) - S += "namespace "; - else if (isa<ObjCMethodDecl>(ND)) - S += "method "; - else if (isa<FunctionDecl>(ND)) - S += "function "; - - S += "'"; - ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); - S += "'"; - } - NeedQuotes = false; - break; - } - } - - if (NeedQuotes) - Output.push_back('\''); - - Output.append(S.begin(), S.end()); - - if (NeedQuotes) - Output.push_back('\''); -} - - static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) { if (C.getLangOptions().CPlusPlus) return CXXRecordDecl::Create(C, TagDecl::TK_struct, @@ -363,14 +121,15 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), NonInstantiationEntries(0), - CurrentInstantiationScope(0) + CurrentInstantiationScope(0), TyposCorrected(0) { TUScope = 0; if (getLangOptions().CPlusPlus) FieldCollector.reset(new CXXFieldCollector()); // Tell diagnostics how to render things from the AST library. - PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context); + PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument, + &Context); ExprEvalContexts.push_back( ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); @@ -426,6 +185,12 @@ void Sema::DeleteStmt(StmtTy *S) { /// popped. void Sema::ActOnEndOfTranslationUnit() { + // Remove functions that turned out to be used. + UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), + UnusedStaticFuncs.end(), + std::mem_fun(&FunctionDecl::isUsed)), + UnusedStaticFuncs.end()); + while (1) { // C++: Perform implicit template instantiations. // @@ -472,12 +237,14 @@ void Sema::ActOnEndOfTranslationUnit() { // translation unit contains a file scope declaration of that // identifier, with the composite type as of the end of the // translation unit, with an initializer equal to 0. - for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) { - VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]); - - // If the tentative definition was completed, it will be in the list, but - // not the map. - if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context)) + llvm::SmallSet<VarDecl *, 32> Seen; + for (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) { + VarDecl *VD = TentativeDefinitions[i]->getActingDefinition(); + + // If the tentative definition was completed, getActingDefinition() returns + // null. If we've already seen this variable before, insert()'s second + // return value is false. + if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD)) continue; if (const IncompleteArrayType *ArrayT @@ -504,6 +271,15 @@ void Sema::ActOnEndOfTranslationUnit() { Consumer.CompleteTentativeDefinition(VD); } + + // Output warning for unused functions. + for (std::vector<FunctionDecl*>::iterator + F = UnusedStaticFuncs.begin(), + FEnd = UnusedStaticFuncs.end(); + F != FEnd; + ++F) + Diag((*F)->getLocation(), diag::warn_unused_function) << (*F)->getDeclName(); + } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 06e9e3ae9e64..3c7492af6108 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -60,6 +60,7 @@ namespace clang { class CallExpr; class DeclRefExpr; class UnresolvedLookupExpr; + class UnresolvedMemberExpr; class VarDecl; class ParmVarDecl; class TypedefDecl; @@ -95,6 +96,7 @@ namespace clang { class ObjCPropertyDecl; class ObjCContainerDecl; class FunctionProtoType; + class CXXBasePath; class CXXBasePaths; class CXXTemporary; class LookupResult; @@ -103,6 +105,7 @@ namespace clang { class InitializationSequence; class VisibleDeclConsumer; class TargetAttributesSema; + class ADLResult; /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. @@ -150,7 +153,7 @@ class LocInfoType : public Type { enum { // The last number that can fit in Type's TC. // Avoids conflict with an existing Type class. - LocInfo = (1 << TypeClassBitSize) - 1 + LocInfo = Type::TypeLast + 1 }; TypeSourceInfo *DeclInfo; @@ -270,18 +273,124 @@ public: /// not visible. llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls; - /// \brief The set of tentative declarations seen so far in this - /// translation unit for which no definition has been seen. - /// - /// The tentative declarations are indexed by the name of the - /// declaration, and only the most recent tentative declaration for - /// a given variable will be recorded here. - llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions; - std::vector<DeclarationName> TentativeDefinitionList; + /// \brief All the tentative definitions encountered in the TU. + std::vector<VarDecl *> TentativeDefinitions; + + /// \brief The set of static functions seen so far that have not been used. + std::vector<FunctionDecl*> UnusedStaticFuncs; + + /// An enum describing the kind of diagnostics to use when checking + /// access. + enum AccessDiagnosticsKind { + /// Suppress diagnostics. + ADK_quiet, + + /// Use the normal diagnostics. + ADK_normal, + + /// Use the diagnostics appropriate for checking a covariant + /// return type. + ADK_covariance + }; + + class AccessedEntity { + public: + enum Kind { + /// A member declaration found through lookup. The target is the + /// member. + Member, + + /// A base-to-derived conversion. The target is the base class. + BaseToDerivedConversion, + + /// A derived-to-base conversion. The target is the base class. + DerivedToBaseConversion + }; + + bool isMemberAccess() const { return K == Member; } + + static AccessedEntity makeMember(CXXRecordDecl *NamingClass, + AccessSpecifier Access, + NamedDecl *Target) { + AccessedEntity E; + E.K = Member; + E.Access = Access; + E.Target = Target; + E.NamingClass = NamingClass; + return E; + } + + static AccessedEntity makeBaseClass(bool BaseToDerived, + CXXRecordDecl *BaseClass, + CXXRecordDecl *DerivedClass, + AccessSpecifier Access) { + AccessedEntity E; + E.K = BaseToDerived ? BaseToDerivedConversion : DerivedToBaseConversion; + E.Access = Access; + E.Target = BaseClass; + E.NamingClass = DerivedClass; + return E; + } + + Kind getKind() const { return Kind(K); } + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } + + // These apply to member decls... + NamedDecl *getTargetDecl() const { return Target; } + CXXRecordDecl *getNamingClass() const { return NamingClass; } + + // ...and these apply to hierarchy conversions. + CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); } + CXXRecordDecl *getDerivedClass() const { return NamingClass; } + + private: + unsigned K : 2; + unsigned Access : 2; + NamedDecl *Target; + CXXRecordDecl *NamingClass; + }; - /// \brief The collection of delayed deprecation warnings. - llvm::SmallVector<std::pair<SourceLocation,NamedDecl*>, 8> - DelayedDeprecationWarnings; + struct DelayedDiagnostic { + enum DDKind { Deprecation, Access }; + + unsigned char Kind; // actually a DDKind + bool Triggered; + + SourceLocation Loc; + + union { + /// Deprecation. + struct { NamedDecl *Decl; } DeprecationData; + + /// Access control. + AccessedEntity AccessData; + }; + + static DelayedDiagnostic makeDeprecation(SourceLocation Loc, + NamedDecl *D) { + DelayedDiagnostic DD; + DD.Kind = Deprecation; + DD.Triggered = false; + DD.Loc = Loc; + DD.DeprecationData.Decl = D; + return DD; + } + + static DelayedDiagnostic makeAccess(SourceLocation Loc, + const AccessedEntity &Entity) { + DelayedDiagnostic DD; + DD.Kind = Access; + DD.Triggered = false; + DD.Loc = Loc; + DD.AccessData = Entity; + return DD; + } + + }; + + /// \brief The stack of diagnostics that were delayed due to being + /// produced during the parsing of a declaration. + llvm::SmallVector<DelayedDiagnostic, 8> DelayedDiagnostics; /// \brief The depth of the current ParsingDeclaration stack. /// If nonzero, we are currently parsing a declaration (and @@ -517,8 +626,8 @@ public: //===--------------------------------------------------------------------===// // Type Analysis / Processing: SemaType.cpp. // + QualType adjustParameterType(QualType T); - void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL); QualType BuildPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, @@ -548,13 +657,15 @@ public: static QualType GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo = 0); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); + bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); bool CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); bool CheckEquivalentExceptionSpec( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc); + const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingEmptyExceptionSpecification = 0); bool CheckExceptionSpecSubset( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Superset, SourceLocation SuperLoc, @@ -634,6 +745,7 @@ public: bool &OverloadableAttrRequired); void CheckMain(FunctionDecl *FD); virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D); + virtual void ActOnObjCCatchParam(DeclPtrTy D); virtual void ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, ExprArg defarg); @@ -950,31 +1062,38 @@ public: // Members have to be NamespaceDecl* or TranslationUnitDecl*. // TODO: make this is a typesafe union. typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet; - - typedef llvm::SmallPtrSet<AnyFunctionDecl, 16> FunctionSet; typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet; + void AddOverloadCandidate(NamedDecl *Function, + AccessSpecifier Access, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet &CandidateSet); + void AddOverloadCandidate(FunctionDecl *Function, + AccessSpecifier Access, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false, bool PartialOverloading = false); - void AddFunctionCandidates(const FunctionSet &Functions, + void AddFunctionCandidates(const UnresolvedSetImpl &Functions, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); - void AddMethodCandidate(NamedDecl *Decl, - QualType ObjectType, Expr **Args, unsigned NumArgs, + void AddMethodCandidate(NamedDecl *Decl, AccessSpecifier Access, + QualType ObjectType, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false, bool ForceRValue = false); - void AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, - QualType ObjectType, Expr **Args, unsigned NumArgs, + void AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + AccessSpecifier Access, CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, @@ -983,20 +1102,24 @@ public: bool SuppressUserConversions = false, bool ForceRValue = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, + AccessSpecifier Access, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); void AddConversionCandidate(CXXConversionDecl *Conversion, + AccessSpecifier Access, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + AccessSpecifier Access, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet); void AddSurrogateCandidate(CXXConversionDecl *Conversion, + AccessSpecifier Access, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, QualType ObjectTy, Expr **Args, unsigned NumArgs, @@ -1021,12 +1144,14 @@ public: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, + bool Operator, Expr **Args, unsigned NumArgs, const TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); bool isBetterOverloadCandidate(const OverloadCandidate& Cand1, - const OverloadCandidate& Cand2); + const OverloadCandidate& Cand2, + SourceLocation Loc); OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet, SourceLocation Loc, OverloadCandidateSet::iterator& Best); @@ -1072,12 +1197,12 @@ public: OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned Opc, - FunctionSet &Functions, + const UnresolvedSetImpl &Fns, ExprArg input); OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc, unsigned Opc, - FunctionSet &Functions, + const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS); OwningExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, @@ -1217,16 +1342,15 @@ public: bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); - ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, - FunctionSet &Functions); + UnresolvedSetImpl &Functions); void ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, - FunctionSet &Functions); + ADLResult &Functions); void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer); @@ -1302,6 +1426,14 @@ public: void CollectImmediateProperties(ObjCContainerDecl *CDecl, llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap); + /// LookupPropertyDecl - Looks up a property in the current class and all + /// its protocols. + ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl, + IdentifierInfo *II); + + ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, + IdentifierInfo *NameII); + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. @@ -1373,6 +1505,8 @@ public: SourceLocation ElseLoc, StmtArg ElseVal); virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, DeclPtrTy CondVar); + virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, + StmtArg Body); virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body); virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, @@ -1416,7 +1550,7 @@ public: bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, - std::string *Names, + IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, ExprArg AsmString, @@ -1466,6 +1600,8 @@ public: void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D); void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc); + void HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, Decl *Ctx); + //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. @@ -1770,7 +1906,8 @@ public: // Act on C++ namespaces virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, IdentifierInfo *Ident, - SourceLocation LBrace); + SourceLocation LBrace, + AttributeList *AttrList); virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace); virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, @@ -1847,7 +1984,8 @@ public: QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg Exprs, - bool RequiresZeroInit = false); + bool RequiresZeroInit = false, + bool BaseInitialization = false); // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? @@ -1856,13 +1994,8 @@ public: CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, - bool RequiresZeroInit = false); - - OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons, - QualType writtenTy, - SourceLocation tyBeginLoc, - MultiExprArg Args, - SourceLocation rParenLoc); + bool RequiresZeroInit = false, + bool BaseInitialization = false); OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc, QualType Ty, @@ -1878,7 +2011,7 @@ public: /// FinalizeVarWithDestructor - Prepare for calling destructor on the /// constructed variable. - void FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType); + void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); /// DefineImplicitDefaultConstructor - Checks for feasibility of /// defining this constructor as the default constructor. @@ -1917,14 +2050,6 @@ public: Expr **Args, unsigned NumArgs, SourceLocation Loc, InitializationKind Kind); - - CXXConstructorDecl * - PerformInitializationByConstructor(QualType ClassType, - MultiExprArg ArgsPtr, - SourceLocation Loc, SourceRange Range, - DeclarationName InitEntity, - InitializationKind Kind, - ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs); bool CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, @@ -2218,9 +2343,10 @@ public: CXXRecordDecl *ClassDecl); bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers, - bool IsImplicitConstructor); + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers, + bool IsImplicitConstructor, + bool AnyErrors); /// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl, /// mark all its non-trivial member and base destructor declarations @@ -2252,7 +2378,8 @@ public: virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, - MemInitTy **MemInits, unsigned NumMemInits); + MemInitTy **MemInits, unsigned NumMemInits, + bool AnyErrors); void CheckCompletedCXXClass(CXXRecordDecl *Record); virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, @@ -2326,7 +2453,7 @@ public: SourceLocation Loc, SourceRange Range, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, - unsigned InaccessibleBaseID, + AccessDiagnosticsKind ADK, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name); @@ -2353,22 +2480,43 @@ public: // C++ Access Control // + enum AccessResult { + AR_accessible, + AR_inaccessible, + AR_dependent, + AR_delayed + }; + bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, NamedDecl *PrevMemberDecl, AccessSpecifier LexicalAS); - const CXXBaseSpecifier *FindInaccessibleBase(QualType Derived, QualType Base, - CXXBasePaths &Paths, - bool NoPrivileges = false); - - void CheckAccess(const LookupResult &R); - bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access); - - bool CheckBaseClassAccess(QualType Derived, QualType Base, - unsigned InaccessibleBaseID, - CXXBasePaths& Paths, SourceLocation AccessLoc, - DeclarationName Name); - + AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, + NamedDecl *D, + AccessSpecifier Access); + AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, + NamedDecl *D, + AccessSpecifier Access); + AccessResult CheckConstructorAccess(SourceLocation Loc, + CXXConstructorDecl *D, + AccessSpecifier Access); + AccessResult CheckDestructorAccess(SourceLocation Loc, + const RecordType *Record); + AccessResult CheckMemberOperatorAccess(SourceLocation Loc, + Expr *ObjectExpr, + NamedDecl *D, + AccessSpecifier Access); + AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, + bool IsBaseToDerived, + QualType Base, QualType Derived, + const CXXBasePath &Path, + bool ForceCheck = false, + bool ForceUnprivileged = false, + AccessDiagnosticsKind ADK = ADK_normal); + + void CheckLookupAccess(const LookupResult &R); + + void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx); enum AbstractDiagSelID { AbstractNone = -1, @@ -2758,17 +2906,28 @@ public: /// TemplateArgumentList *Deduced; + /// \brief The source location at which template argument + /// deduction is occurring. + SourceLocation Loc; + // do not implement these TemplateDeductionInfo(const TemplateDeductionInfo&); TemplateDeductionInfo &operator=(const TemplateDeductionInfo&); public: - TemplateDeductionInfo(ASTContext &Context) : Context(Context), Deduced(0) { } + TemplateDeductionInfo(ASTContext &Context, SourceLocation Loc) + : Context(Context), Deduced(0), Loc(Loc) { } ~TemplateDeductionInfo() { // FIXME: if (Deduced) Deduced->Destroy(Context); } + /// \brief Returns the location at which template argument is + /// occuring. + SourceLocation getLocation() const { + return Loc; + } + /// \brief Take ownership of the deduced template argument list. TemplateArgumentList *take() { TemplateArgumentList *Result = Deduced; @@ -2866,20 +3025,21 @@ public: FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, + SourceLocation Loc, TemplatePartialOrderingContext TPOC); - FunctionDecl *getMostSpecialized(FunctionDecl **Specializations, - unsigned NumSpecializations, - TemplatePartialOrderingContext TPOC, - SourceLocation Loc, - const PartialDiagnostic &NoneDiag, - const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag, - unsigned *Index = 0); + UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, + UnresolvedSetIterator SEnd, + TemplatePartialOrderingContext TPOC, + SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag); ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, - ClassTemplatePartialSpecializationDecl *PS2); + ClassTemplatePartialSpecializationDecl *PS2, + SourceLocation Loc); void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, @@ -2893,7 +3053,8 @@ public: // MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, - const TemplateArgumentList *Innermost = 0); + const TemplateArgumentList *Innermost = 0, + bool RelativeToPrimary = false); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { @@ -3243,6 +3404,9 @@ public: /// variables. LocalInstantiationScope *CurrentInstantiationScope; + /// \brief The number of typos corrected by CorrectTypo. + unsigned TyposCorrected; + /// \brief An entity for which implicit template instantiation is required. /// /// The source location associated with the declaration is the first place in @@ -3550,6 +3714,11 @@ public: // to their respective pointers (C99 6.3.2.1). void DefaultFunctionArrayConversion(Expr *&expr); + // DefaultFunctionArrayLvalueConversion - converts functions and + // arrays to their respective pointers and performs the + // lvalue-to-rvalue conversion. + void DefaultFunctionArrayLvalueConversion(Expr *&expr); + // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that // do not have a prototype. Integer promotions are performed on each // argument, and arguments that have type float are promoted to double. @@ -3944,12 +4113,15 @@ public: //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system + +public: + SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, + unsigned ByteNo) const; + private: bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); - SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, - unsigned ByteNo) const; bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall); bool CheckObjCString(Expr *Arg); @@ -3957,7 +4129,7 @@ private: CallExpr *TheCall); bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); - bool SemaBuiltinUnaryFP(CallExpr *TheCall); + bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg=1); bool SemaBuiltinStackAddress(CallExpr *TheCall); public: @@ -3987,7 +4159,6 @@ private: const PartialDiagnostic &PD, bool Equality = false); void CheckImplicitConversion(Expr *E, QualType Target); - }; //===--------------------------------------------------------------------===// diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 51f9e300ef90..eca8bb4c2a9b 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -16,6 +16,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" + using namespace clang; /// SetMemberAccessSpecifier - Set the access specifier of a member. @@ -47,192 +49,500 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, return false; } -/// Find a class on the derivation path between Derived and Base that is -/// inaccessible. If @p NoPrivileges is true, special access rights (members -/// and friends) are not considered. -const CXXBaseSpecifier *Sema::FindInaccessibleBase( - QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) { - Base = Context.getCanonicalType(Base).getUnqualifiedType(); - assert(!Paths.isAmbiguous(Base) && - "Can't check base class access if set of paths is ambiguous"); - assert(Paths.isRecordingPaths() && - "Can't check base class access without recorded paths"); - - - const CXXBaseSpecifier *InaccessibleBase = 0; - - const CXXRecordDecl *CurrentClassDecl = 0; - if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl())) - CurrentClassDecl = MD->getParent(); - - for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); - Path != PathsEnd; ++Path) { - - bool FoundInaccessibleBase = false; - - for (CXXBasePath::const_iterator Element = Path->begin(), - ElementEnd = Path->end(); Element != ElementEnd; ++Element) { - const CXXBaseSpecifier *Base = Element->Base; - - switch (Base->getAccessSpecifier()) { - default: - assert(0 && "invalid access specifier"); - case AS_public: - // Nothing to do. - break; - case AS_private: - // FIXME: Check if the current function/class is a friend. - if (NoPrivileges || CurrentClassDecl != Element->Class) - FoundInaccessibleBase = true; - break; - case AS_protected: - // FIXME: Implement - break; - } +namespace { +struct EffectiveContext { + EffectiveContext() : Record(0), Function(0) {} + + explicit EffectiveContext(DeclContext *DC) { + if (isa<FunctionDecl>(DC)) { + Function = cast<FunctionDecl>(DC); + DC = Function->getDeclContext(); + } else + Function = 0; + + if (isa<CXXRecordDecl>(DC)) + Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); + else + Record = 0; + } + + bool isClass(const CXXRecordDecl *R) const { + return R->getCanonicalDecl() == Record; + } + + CXXRecordDecl *Record; + FunctionDecl *Function; +}; +} + +static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { + CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext()); + while (DeclaringClass->isAnonymousStructOrUnion()) + DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); + return DeclaringClass; +} + +static Sema::AccessResult GetFriendKind(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *Class) { + if (EC.isClass(Class)) + return Sema::AR_accessible; + + // FIXME: implement + return Sema::AR_inaccessible; +} - if (FoundInaccessibleBase) { - InaccessibleBase = Base; - break; +/// Finds the best path from the naming class to the declaring class, +/// taking friend declarations into account. +/// +/// \return null if friendship is dependent +static CXXBasePath *FindBestPath(Sema &S, + const EffectiveContext &EC, + CXXRecordDecl *Derived, + CXXRecordDecl *Base, + CXXBasePaths &Paths) { + // Derive the paths to the desired base. + bool isDerived = Derived->isDerivedFrom(Base, Paths); + assert(isDerived && "derived class not actually derived from base"); + (void) isDerived; + + CXXBasePath *BestPath = 0; + + // Derive the friend-modified access along each path. + for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); + PI != PE; ++PI) { + + // Walk through the path backwards. + AccessSpecifier PathAccess = AS_public; + CXXBasePath::iterator I = PI->end(), E = PI->begin(); + while (I != E) { + --I; + + AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); + if (BaseAccess != AS_public) { + switch (GetFriendKind(S, EC, I->Class)) { + case Sema::AR_inaccessible: break; + case Sema::AR_accessible: BaseAccess = AS_public; break; + case Sema::AR_dependent: return 0; + case Sema::AR_delayed: + llvm_unreachable("friend resolution is never delayed"); break; + } } + + PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess); } - if (!FoundInaccessibleBase) { - // We found a path to the base, our work here is done. - return 0; + // Note that we modify the path's Access field to the + // friend-modified access. + if (BestPath == 0 || PathAccess < BestPath->Access) { + BestPath = &*PI; + BestPath->Access = PathAccess; } } - assert(InaccessibleBase && "no path found, but no inaccessible base"); - return InaccessibleBase; + return BestPath; } -/// CheckBaseClassAccess - Check that a derived class can access its base class -/// and report an error if it can't. [class.access.base] -bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, - unsigned InaccessibleBaseID, - CXXBasePaths &Paths, SourceLocation AccessLoc, - DeclarationName Name) { +/// Diagnose the path which caused the given declaration or base class +/// to become inaccessible. +static void DiagnoseAccessPath(Sema &S, + const EffectiveContext &EC, + CXXRecordDecl *NamingClass, + CXXRecordDecl *DeclaringClass, + NamedDecl *D, AccessSpecifier Access) { + // 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)) { + case Sema::AR_inaccessible: { + S.Diag(D->getLocation(), diag::note_access_natural) + << (unsigned) (Access == AS_protected) + << /*FIXME: not implicitly*/ 0; + return; + } - if (!getLangOptions().AccessControl) - return false; - const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase( - Derived, Base, Paths); + case Sema::AR_accessible: break; - if (InaccessibleBase) { - Diag(AccessLoc, InaccessibleBaseID) - << Derived << Base << Name; + case Sema::AR_dependent: + case Sema::AR_delayed: + llvm_unreachable("dependent/delayed not allowed"); + return; + } + } - AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten(); + CXXBasePaths Paths; + CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths); - // If there's no written access specifier, then the inheritance specifier - // is implicitly private. - if (AS == AS_none) - Diag(InaccessibleBase->getSourceRange().getBegin(), - diag::note_inheritance_implicitly_private_here); - else - Diag(InaccessibleBase->getSourceRange().getBegin(), - diag::note_inheritance_specifier_here) << AS; + CXXBasePath::iterator I = Path.end(), E = Path.begin(); + while (I != E) { + --I; - return true; + const CXXBaseSpecifier *BS = I->Base; + AccessSpecifier BaseAccess = BS->getAccessSpecifier(); + + // If this is public inheritance, or the derived class is a friend, + // skip this step. + if (BaseAccess == AS_public) + continue; + + switch (GetFriendKind(S, EC, I->Class)) { + case Sema::AR_accessible: continue; + case Sema::AR_inaccessible: break; + + case Sema::AR_dependent: + case Sema::AR_delayed: + llvm_unreachable("dependent friendship, should not be diagnosing"); + } + + // Check whether this base specifier is the tighest point + // constraining access. We have to check against AS_private for + // the same reasons as above. + if (BaseAccess == AS_private || BaseAccess >= Access) { + + // We're constrained by inheritance, but we want to say + // "declared private here" if we're diagnosing a hierarchy + // conversion and this is the final step. + unsigned diagnostic; + if (D) diagnostic = diag::note_access_constrained_by_path; + else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural; + else diagnostic = diag::note_access_constrained_by_path; + + S.Diag(BS->getSourceRange().getBegin(), diagnostic) + << BS->getSourceRange() + << (BaseAccess == AS_protected) + << (BS->getAccessSpecifierAsWritten() == AS_none); + return; + } } - return false; + llvm_unreachable("access not apparently constrained by path"); } -/// Diagnose the path which caused the given declaration to become -/// inaccessible. -static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D, - AccessSpecifier Access) { - // Easy case: the decl's natural access determined its path access. - if (Access == D->getAccess() || D->getAccess() == AS_private) { - S.Diag(D->getLocation(), diag::note_access_natural) - << (unsigned) (Access == AS_protected); - return; +/// 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); + + if (isa<CXXConstructorDecl>(D)) { + unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected + : diag::err_access_ctor_private); + S.Diag(Loc, DiagID) + << S.Context.getTypeDeclType(DeclaringClass); + } else { + unsigned DiagID = (Access == AS_protected ? diag::err_access_protected + : diag::err_access_private); + S.Diag(Loc, DiagID) + << D->getDeclName() + << S.Context.getTypeDeclType(DeclaringClass); } + DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access); +} - // TODO: flesh this out - S.Diag(D->getLocation(), diag::note_access_constrained_by_path) - << (unsigned) (Access == AS_protected); +/// Diagnose an inaccessible hierarchy conversion. +static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc, + const EffectiveContext &EC, + AccessSpecifier Access, + const Sema::AccessedEntity &Entity, + Sema::AccessDiagnosticsKind ADK) { + if (ADK == Sema::ADK_covariance) { + S.Diag(Loc, diag::err_covariant_return_inaccessible_base) + << S.Context.getTypeDeclType(Entity.getDerivedClass()) + << S.Context.getTypeDeclType(Entity.getBaseClass()) + << (Access == AS_protected); + } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) { + S.Diag(Loc, diag::err_downcast_from_inaccessible_base) + << S.Context.getTypeDeclType(Entity.getDerivedClass()) + << S.Context.getTypeDeclType(Entity.getBaseClass()) + << (Access == AS_protected); + } else { + S.Diag(Loc, diag::err_upcast_to_inaccessible_base) + << S.Context.getTypeDeclType(Entity.getDerivedClass()) + << S.Context.getTypeDeclType(Entity.getBaseClass()) + << (Access == AS_protected); + } + DiagnoseAccessPath(S, EC, Entity.getDerivedClass(), + Entity.getBaseClass(), 0, Access); } -/// Checks access to the given declaration in the current context. -/// -/// \param R the means via which the access was made; must have a naming -/// class set -/// \param D the declaration accessed -/// \param Access the best access along any inheritance path from the -/// naming class to the declaration. AS_none means the path is impossible -bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D, - AccessSpecifier Access) { - assert(R.getNamingClass() && "performing access check without naming class"); +static void DiagnoseBadAccess(Sema &S, + SourceLocation Loc, + const EffectiveContext &EC, + CXXRecordDecl *NamingClass, + AccessSpecifier Access, + const Sema::AccessedEntity &Entity, + Sema::AccessDiagnosticsKind ADK) { + if (Entity.isMemberAccess()) + DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity); + else + DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK); +} - // If the access path is public, it's accessible everywhere. - if (Access == AS_public) - return false; - // Otherwise, derive the current class context. - DeclContext *DC = CurContext; - while (isa<CXXRecordDecl>(DC) && - cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion()) - DC = DC->getParent(); - - CXXRecordDecl *CurRecord; - if (isa<CXXRecordDecl>(DC)) - CurRecord = cast<CXXRecordDecl>(DC); - else if (isa<CXXMethodDecl>(DC)) - CurRecord = cast<CXXMethodDecl>(DC)->getParent(); - else { - Diag(R.getNameLoc(), diag::err_access_outside_class) - << (Access == AS_protected); - DiagnoseAccessPath(*this, R, D, Access); - return true; +/// 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) { + CXXRecordDecl *DeclaringClass; + if (Entity.isMemberAccess()) { + DeclaringClass = FindDeclaringClass(Entity.getTargetDecl()); + } else { + DeclaringClass = Entity.getBaseClass(); } + CXXRecordDecl *NamingClass = Entity.getNamingClass(); + + // Adjust the declaration of the referred entity. + AccessSpecifier DeclAccess = AS_none; + if (Entity.isMemberAccess()) { + 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"); + } + } + + if (DeclaringClass == NamingClass) { + Access = DeclAccess; + return; + } + } + + assert(DeclaringClass != NamingClass); - CXXRecordDecl *NamingClass = R.getNamingClass(); + // Append the declaration's access if applicable. + CXXBasePaths Paths; + CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(), + DeclaringClass, Paths); + if (!Path) { + // FIXME: delay dependent friendship + return; + } + + // Grab the access along the best path. + AccessSpecifier NewAccess = Path->Access; + if (Entity.isMemberAccess()) + NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess); + + assert(NewAccess <= Access && "access along best path worse than direct?"); + Access = NewAccess; +} + +/// 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, + Sema::AccessDiagnosticsKind ADK) { + AccessSpecifier Access = Entity.getAccess(); + assert(Access != AS_public); + + CXXRecordDecl *NamingClass = Entity.getNamingClass(); while (NamingClass->isAnonymousStructOrUnion()) // This should be guaranteed by the fact that the decl has // non-public access. If not, we should make it guaranteed! NamingClass = cast<CXXRecordDecl>(NamingClass); + if (!EC.Record) { + TryElevateAccess(S, EC, Entity, Access); + if (Access == AS_public) return Sema::AR_accessible; + + if (ADK != Sema::ADK_quiet) + DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK); + return Sema::AR_inaccessible; + } + // White-list accesses from within the declaring class. - if (Access != AS_none && - CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl()) - return false; + if (Access != AS_none && EC.isClass(NamingClass)) + return Sema::AR_accessible; + + // If the access is worse than 'protected', try to promote to it using + // friend declarations. + bool TriedElevation = false; + if (Access != AS_protected) { + TryElevateAccess(S, EC, Entity, Access); + if (Access == AS_public) return Sema::AR_accessible; + TriedElevation = true; + } // Protected access. if (Access == AS_protected) { // FIXME: implement [class.protected]p1 - if (CurRecord->isDerivedFrom(NamingClass)) - return false; + if (EC.Record->isDerivedFrom(NamingClass)) + return Sema::AR_accessible; - // FIXME: dependent classes + // FIXME: delay dependent classes } - // FIXME: friends + // We're about to reject; one last chance to promote access. + if (!TriedElevation) { + TryElevateAccess(S, EC, Entity, Access); + if (Access == AS_public) return Sema::AR_accessible; + } + + // Okay, that's it, reject it. + if (ADK != Sema::ADK_quiet) + DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK); + return Sema::AR_inaccessible; +} - // Okay, it's a bad access, reject it. +static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, + const Sema::AccessedEntity &Entity, + Sema::AccessDiagnosticsKind ADK + = Sema::ADK_normal) { + // If the access path is public, it's accessible everywhere. + if (Entity.getAccess() == AS_public) + return Sema::AR_accessible; + + // If we're currently parsing a top-level declaration, delay + // diagnostics. This is the only case where parsing a declaration + // can actually change our effective context for the purposes of + // access control. + if (S.CurContext->isFileContext() && S.ParsingDeclDepth) { + assert(ADK == Sema::ADK_normal && "delaying abnormal access check"); + S.DelayedDiagnostics.push_back( + Sema::DelayedDiagnostic::makeAccess(Loc, Entity)); + return Sema::AR_delayed; + } - - CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext()); + return CheckEffectiveAccess(S, EffectiveContext(S.CurContext), + Loc, Entity, ADK); +} - if (Access == AS_protected) { - Diag(R.getNameLoc(), diag::err_access_protected) - << Context.getTypeDeclType(DeclaringClass) - << Context.getTypeDeclType(CurRecord); - DiagnoseAccessPath(*this, R, D, Access); - return true; - } +void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { + // Pretend we did this from the context of the newly-parsed + // declaration. + EffectiveContext EC(Ctx->getDeclContext()); + + if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal)) + DD.Triggered = true; +} + +Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, + NamedDecl *D, + AccessSpecifier Access) { + if (!getLangOptions().AccessControl || !E->getNamingClass()) + return AR_accessible; - assert(Access == AS_private || Access == AS_none); - Diag(R.getNameLoc(), diag::err_access_private) - << Context.getTypeDeclType(DeclaringClass) - << Context.getTypeDeclType(CurRecord); - DiagnoseAccessPath(*this, R, D, Access); - return true; + return CheckAccess(*this, E->getNameLoc(), + AccessedEntity::makeMember(E->getNamingClass(), Access, D)); +} + +/// Perform access-control checking on a previously-unresolved member +/// access which has now been resolved to a member. +Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, + NamedDecl *D, + AccessSpecifier Access) { + if (!getLangOptions().AccessControl) + return AR_accessible; + + return CheckAccess(*this, E->getMemberLoc(), + AccessedEntity::makeMember(E->getNamingClass(), Access, D)); +} + +Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, + const RecordType *RT) { + if (!getLangOptions().AccessControl) + return AR_accessible; + + CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); + CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context); + + AccessSpecifier Access = Dtor->getAccess(); + if (Access == AS_public) + return AR_accessible; + + return CheckAccess(*this, Loc, + AccessedEntity::makeMember(NamingClass, Access, Dtor)); +} + +/// Checks access to a constructor. +Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, + CXXConstructorDecl *Constructor, + AccessSpecifier Access) { + if (!getLangOptions().AccessControl) + return AR_accessible; + + CXXRecordDecl *NamingClass = Constructor->getParent(); + return CheckAccess(*this, UseLoc, + AccessedEntity::makeMember(NamingClass, Access, Constructor)); +} + +/// Checks access to an overloaded member operator, including +/// conversion operators. +Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, + Expr *ObjectExpr, + NamedDecl *MemberOperator, + AccessSpecifier Access) { + if (!getLangOptions().AccessControl) + return AR_accessible; + + const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>(); + assert(RT && "found member operator but object expr not of record type"); + CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); + + return CheckAccess(*this, OpLoc, + AccessedEntity::makeMember(NamingClass, Access, MemberOperator)); +} + +/// Checks access for a hierarchy conversion. +/// +/// \param IsBaseToDerived whether this is a base-to-derived conversion (true) +/// or a derived-to-base conversion (false) +/// \param ForceCheck true if this check should be performed even if access +/// control is disabled; some things rely on this for semantics +/// \param ForceUnprivileged true if this check should proceed as if the +/// context had no special privileges +/// \param ADK controls the kind of diagnostics that are used +Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, + bool IsBaseToDerived, + QualType Base, + QualType Derived, + const CXXBasePath &Path, + bool ForceCheck, + bool ForceUnprivileged, + AccessDiagnosticsKind ADK) { + if (!ForceCheck && !getLangOptions().AccessControl) + return AR_accessible; + + if (Path.Access == AS_public) + return AR_accessible; + + // TODO: preserve the information about which types exactly were used. + CXXRecordDecl *BaseD, *DerivedD; + BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); + DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); + AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived, + BaseD, DerivedD, + Path.Access); + + if (ForceUnprivileged) + return CheckEffectiveAccess(*this, EffectiveContext(), + AccessLoc, Entity, ADK); + return CheckAccess(*this, AccessLoc, Entity, ADK); } /// Checks access to all the declarations in the given result set. -void Sema::CheckAccess(const LookupResult &R) { +void Sema::CheckLookupAccess(const LookupResult &R) { + assert(getLangOptions().AccessControl + && "performing access check without access control"); + assert(R.getNamingClass() && "performing access check without naming class"); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - CheckAccess(R, *I, I.getAccess()); + if (I.getAccess() != AS_public) + CheckAccess(*this, R.getNameLoc(), + AccessedEntity::makeMember(R.getNamingClass(), + I.getAccess(), *I)); } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 57c4f9bc2a27..0097cd363c8c 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -204,7 +204,30 @@ bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { T2 = T2PtrType->getPointeeType(); return true; } - + const ObjCObjectPointerType *T1ObjCPtrType = + T1->getAs<ObjCObjectPointerType>(), + *T2ObjCPtrType = + T2->getAs<ObjCObjectPointerType>(); + if (T1ObjCPtrType) { + if (T2ObjCPtrType) { + T1 = T1ObjCPtrType->getPointeeType(); + T2 = T2ObjCPtrType->getPointeeType(); + return true; + } + else if (T2PtrType) { + T1 = T1ObjCPtrType->getPointeeType(); + T2 = T2PtrType->getPointeeType(); + return true; + } + } + else if (T2ObjCPtrType) { + if (T1PtrType) { + T2 = T2ObjCPtrType->getPointeeType(); + T1 = T1PtrType->getPointeeType(); + return true; + } + } + const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(), *T2MPType = T2->getAs<MemberPointerType>(); if (T1MPType && T2MPType) { @@ -225,9 +248,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since // the rules are non-trivial. So first we construct Tcv *...cv* as described // in C++ 5.2.11p8. - assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) && + assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType()) && "Source type is not pointer or pointer to member."); - assert((DestType->isPointerType() || DestType->isMemberPointerType()) && + assert((DestType->isAnyPointerType() || DestType->isMemberPointerType()) && "Destination type is not pointer or pointer to member."); QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType), @@ -368,7 +391,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, } // C++ 5.2.7p6: Otherwise, v shall be [polymorphic]. - const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context); + const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(); assert(SrcDecl && "Definition missing"); if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) @@ -388,7 +411,7 @@ void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange) { if (!DestType->isLValueReferenceType()) - Self.DefaultFunctionArrayConversion(SrcExpr); + Self.DefaultFunctionArrayLvalueConversion(SrcExpr); unsigned msg = diag::err_bad_cxx_cast_generic; if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success @@ -407,7 +430,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange, CastExpr::CastKind &Kind) { if (!DestType->isLValueReferenceType()) - Self.DefaultFunctionArrayConversion(SrcExpr); + Self.DefaultFunctionArrayLvalueConversion(SrcExpr); unsigned msg = diag::err_bad_cxx_cast_generic; if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, @@ -434,7 +457,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, } if (!DestType->isLValueReferenceType() && !DestType->isRecordType()) - Self.DefaultFunctionArrayConversion(SrcExpr); + Self.DefaultFunctionArrayLvalueConversion(SrcExpr); unsigned msg = diag::err_bad_cxx_cast_generic; if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, @@ -755,9 +778,10 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, return TC_Failed; } - if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType, - diag::err_downcast_from_inaccessible_base, Paths, - OpRange.getBegin(), DeclarationName())) { + if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(), + /*IsBaseToDerived*/ true, + SrcType, DestType, + Paths.front())) { msg = 0; return TC_Failed; } @@ -821,9 +845,10 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, return TC_Failed; } - if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType, - diag::err_downcast_from_inaccessible_base, Paths, - OpRange.getBegin(), DeclarationName())) { + if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(), + /*IsBaseToDerived*/ false, + DestType, SrcType, + Paths.front())) { msg = 0; return TC_Failed; } @@ -1083,10 +1108,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, return TC_Failed; } - bool destIsPtr = - CStyle? DestType->isAnyPointerType() : DestType->isPointerType(); - bool srcIsPtr = - CStyle ? SrcType->isAnyPointerType() : SrcType->isPointerType(); + bool destIsPtr = DestType->isAnyPointerType(); + bool srcIsPtr = SrcType->isAnyPointerType(); if (!destIsPtr && !srcIsPtr) { // Except for std::nullptr_t->integer and lvalue->reference, which are // handled above, at least one of the two arguments must be a pointer. @@ -1197,7 +1220,7 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, return false; if (!CastTy->isLValueReferenceType() && !CastTy->isRecordType()) - DefaultFunctionArrayConversion(CastExpr); + DefaultFunctionArrayLvalueConversion(CastExpr); // C++ [expr.cast]p5: The conversions performed by // - a const_cast, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 7a0b6252064d..52e9e9bc87ef 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -241,6 +241,10 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { DeclContext *DC = computeDeclContext(SS, true); if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { + // If this is a dependent type, then we consider it complete. + if (Tag->isDependentContext()) + return false; + // If we're currently defining this type, then lookup into the // type is okay: don't complain that it isn't complete yet. const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>(); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 6ff8b1d75371..b62cd19a0b25 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -14,7 +14,8 @@ #include "Sema.h" #include "clang/Analysis/CFG.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/Analyses/PrintfFormatString.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" @@ -140,12 +141,16 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaBuiltinUnorderedCompare(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_fpclassify: + if (SemaBuiltinFPClassification(TheCall, 6)) + return ExprError(); + break; case Builtin::BI__builtin_isfinite: case Builtin::BI__builtin_isinf: case Builtin::BI__builtin_isinf_sign: case Builtin::BI__builtin_isnan: case Builtin::BI__builtin_isnormal: - if (SemaBuiltinUnaryFP(TheCall)) + if (SemaBuiltinFPClassification(TheCall)) return ExprError(); break; case Builtin::BI__builtin_return_address: @@ -583,20 +588,21 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { return false; } -/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isnan and -/// friends. This is declared to take (...), so we have to check everything. -bool Sema::SemaBuiltinUnaryFP(CallExpr *TheCall) { - if (TheCall->getNumArgs() < 1) +/// SemaBuiltinSemaBuiltinFPClassification - Handle functions like +/// __builtin_isnan and friends. This is declared to take (...), so we have +/// to check everything. +bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg) { + if (TheCall->getNumArgs() < LastArg) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) << 0 /*function call*/; - if (TheCall->getNumArgs() > 1) - return Diag(TheCall->getArg(1)->getLocStart(), + if (TheCall->getNumArgs() > LastArg) + return Diag(TheCall->getArg(LastArg)->getLocStart(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ - << SourceRange(TheCall->getArg(1)->getLocStart(), + << SourceRange(TheCall->getArg(LastArg)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); - Expr *OrigArg = TheCall->getArg(0); + Expr *OrigArg = TheCall->getArg(LastArg-1); if (OrigArg->isTypeDependent()) return false; @@ -748,7 +754,7 @@ bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) { if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context)) return Diag(TheCall->getLocStart(), diag::err_expr_not_ice) << TheCall->getArg(0)->getSourceRange(); - + return false; } @@ -845,8 +851,7 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, } if (isConstant) { - const VarDecl *Def = 0; - if (const Expr *Init = VD->getDefinition(Def)) + if (const Expr *Init = VD->getAnyInitializer()) return SemaCheckStringLiteral(Init, TheCall, HasVAListArg, format_idx, firstDataArg); } @@ -925,7 +930,7 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end(); i != e; ++i) { const Expr *ArgExpr = TheCall->getArg(*i); - if (ArgExpr->isNullPointerConstant(Context, + if (ArgExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg) << ArgExpr->getSourceRange(); @@ -1032,248 +1037,309 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, << OrigFormatExpr->getSourceRange(); } -void Sema::CheckPrintfString(const StringLiteral *FExpr, - const Expr *OrigFormatExpr, - const CallExpr *TheCall, bool HasVAListArg, - unsigned format_idx, unsigned firstDataArg) { - - const ObjCStringLiteral *ObjCFExpr = - dyn_cast<ObjCStringLiteral>(OrigFormatExpr); - - // CHECK: is the format string a wide literal? - if (FExpr->isWide()) { - Diag(FExpr->getLocStart(), - diag::warn_printf_format_string_is_wide_literal) - << OrigFormatExpr->getSourceRange(); - return; - } +namespace { +class CheckPrintfHandler : public analyze_printf::FormatStringHandler { + Sema &S; + const StringLiteral *FExpr; + const Expr *OrigFormatExpr; + unsigned NumConversions; + const unsigned NumDataArgs; + const bool IsObjCLiteral; + const char *Beg; // Start of format string. + const bool HasVAListArg; + const CallExpr *TheCall; + unsigned FormatIdx; +public: + CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, + const Expr *origFormatExpr, + unsigned numDataArgs, bool isObjCLiteral, + const char *beg, bool hasVAListArg, + const CallExpr *theCall, unsigned formatIdx) + : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), + NumConversions(0), NumDataArgs(numDataArgs), + IsObjCLiteral(isObjCLiteral), Beg(beg), + HasVAListArg(hasVAListArg), + TheCall(theCall), FormatIdx(formatIdx) {} + + void DoneProcessing(); + + void HandleIncompleteFormatSpecifier(const char *startSpecifier, + unsigned specifierLen); + + void + HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen); + + void HandleNullChar(const char *nullCharacter); + + bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen); +private: + SourceRange getFormatStringRange(); + SourceRange getFormatSpecifierRange(const char *startSpecifier, + unsigned specifierLen); + SourceLocation getLocationOfByte(const char *x); + + bool HandleAmount(const analyze_printf::OptionalAmount &Amt, + unsigned MissingArgDiag, unsigned BadTypeDiag, + const char *startSpecifier, unsigned specifierLen); + void HandleFlags(const analyze_printf::FormatSpecifier &FS, + llvm::StringRef flag, llvm::StringRef cspec, + const char *startSpecifier, unsigned specifierLen); + + const Expr *getDataArg(unsigned i) const; +}; +} - // Str - The format string. NOTE: this is NOT null-terminated! - const char *Str = FExpr->getStrData(); +SourceRange CheckPrintfHandler::getFormatStringRange() { + return OrigFormatExpr->getSourceRange(); +} - // CHECK: empty format string? - unsigned StrLen = FExpr->getByteLength(); +SourceRange CheckPrintfHandler:: +getFormatSpecifierRange(const char *startSpecifier, unsigned specifierLen) { + return SourceRange(getLocationOfByte(startSpecifier), + getLocationOfByte(startSpecifier+specifierLen-1)); +} - if (StrLen == 0) { - Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string) - << OrigFormatExpr->getSourceRange(); - return; - } +SourceLocation CheckPrintfHandler::getLocationOfByte(const char *x) { + return S.getLocationOfStringLiteralByte(FExpr, x - Beg); +} - // We process the format string using a binary state machine. The - // current state is stored in CurrentState. - enum { - state_OrdChr, - state_Conversion - } CurrentState = state_OrdChr; +void CheckPrintfHandler:: +HandleIncompleteFormatSpecifier(const char *startSpecifier, + unsigned specifierLen) { + SourceLocation Loc = getLocationOfByte(startSpecifier); + S.Diag(Loc, diag::warn_printf_incomplete_specifier) + << getFormatSpecifierRange(startSpecifier, specifierLen); +} - // numConversions - The number of conversions seen so far. This is - // incremented as we traverse the format string. - unsigned numConversions = 0; +void CheckPrintfHandler:: +HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + + ++NumConversions; + const analyze_printf::ConversionSpecifier &CS = + FS.getConversionSpecifier(); + SourceLocation Loc = getLocationOfByte(CS.getStart()); + S.Diag(Loc, diag::warn_printf_invalid_conversion) + << llvm::StringRef(CS.getStart(), CS.getLength()) + << getFormatSpecifierRange(startSpecifier, specifierLen); +} - // numDataArgs - The number of data arguments after the format - // string. This can only be determined for non vprintf-like - // functions. For those functions, this value is 1 (the sole - // va_arg argument). - unsigned numDataArgs = TheCall->getNumArgs()-firstDataArg; +void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) { + // The presence of a null character is likely an error. + S.Diag(getLocationOfByte(nullCharacter), + diag::warn_printf_format_string_contains_null_char) + << getFormatStringRange(); +} - // Inspect the format string. - unsigned StrIdx = 0; +const Expr *CheckPrintfHandler::getDataArg(unsigned i) const { + return TheCall->getArg(FormatIdx + i); +} - // LastConversionIdx - Index within the format string where we last saw - // a '%' character that starts a new format conversion. - unsigned LastConversionIdx = 0; - for (; StrIdx < StrLen; ++StrIdx) { - // Is the number of detected conversion conversions greater than - // the number of matching data arguments? If so, stop. - if (!HasVAListArg && numConversions > numDataArgs) break; +void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS, + llvm::StringRef flag, + llvm::StringRef cspec, + const char *startSpecifier, + unsigned specifierLen) { + const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier(); + S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_nonsensical_flag) + << flag << cspec << getFormatSpecifierRange(startSpecifier, specifierLen); +} - // Handle "\0" - if (Str[StrIdx] == '\0') { - // The string returned by getStrData() is not null-terminated, - // so the presence of a null character is likely an error. - Diag(getLocationOfStringLiteralByte(FExpr, StrIdx), - diag::warn_printf_format_string_contains_null_char) - << OrigFormatExpr->getSourceRange(); - return; - } +bool +CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt, + unsigned MissingArgDiag, + unsigned BadTypeDiag, + const char *startSpecifier, + unsigned specifierLen) { + + if (Amt.hasDataArgument()) { + ++NumConversions; + if (!HasVAListArg) { + if (NumConversions > NumDataArgs) { + S.Diag(getLocationOfByte(Amt.getStart()), MissingArgDiag) + << getFormatSpecifierRange(startSpecifier, specifierLen); + // Don't do any more checking. We will just emit + // spurious errors. + return false; + } - // Ordinary characters (not processing a format conversion). - if (CurrentState == state_OrdChr) { - if (Str[StrIdx] == '%') { - CurrentState = state_Conversion; - LastConversionIdx = StrIdx; + // Type check the data argument. It should be an 'int'. + // Although not in conformance with C99, we also allow the argument to be + // an 'unsigned int' as that is a reasonably safe case. GCC also + // doesn't emit a warning for that case. + const Expr *Arg = getDataArg(NumConversions); + QualType T = Arg->getType(); + + const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context); + assert(ATR.isValid()); + + if (!ATR.matchesType(S.Context, T)) { + S.Diag(getLocationOfByte(Amt.getStart()), BadTypeDiag) + << ATR.getRepresentativeType(S.Context) << T + << getFormatSpecifierRange(startSpecifier, specifierLen) + << Arg->getSourceRange(); + // Don't do any more checking. We will just emit + // spurious errors. + return false; } - continue; } + } + return true; +} - // Seen '%'. Now processing a format conversion. - switch (Str[StrIdx]) { - // Handle dynamic precision or width specifier. - case '*': { - ++numConversions; - - if (!HasVAListArg) { - if (numConversions > numDataArgs) { - SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx); - - if (Str[StrIdx-1] == '.') - Diag(Loc, diag::warn_printf_asterisk_precision_missing_arg) - << OrigFormatExpr->getSourceRange(); - else - Diag(Loc, diag::warn_printf_asterisk_width_missing_arg) - << OrigFormatExpr->getSourceRange(); - - // Don't do any more checking. We'll just emit spurious errors. - return; - } +bool +CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier + &FS, + const char *startSpecifier, + unsigned specifierLen) { + + using namespace analyze_printf; + const ConversionSpecifier &CS = FS.getConversionSpecifier(); + + // First check if the field width, precision, and conversion specifier + // have matching data arguments. + if (!HandleAmount(FS.getFieldWidth(), + diag::warn_printf_asterisk_width_missing_arg, + diag::warn_printf_asterisk_width_wrong_type, + startSpecifier, specifierLen)) { + return false; + } - // Perform type checking on width/precision specifier. - const Expr *E = TheCall->getArg(format_idx+numConversions); - if (const BuiltinType *BT = E->getType()->getAs<BuiltinType>()) - if (BT->getKind() == BuiltinType::Int) - break; + if (!HandleAmount(FS.getPrecision(), + diag::warn_printf_asterisk_precision_missing_arg, + diag::warn_printf_asterisk_precision_wrong_type, + startSpecifier, specifierLen)) { + return false; + } - SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx); + // Check for using an Objective-C specific conversion specifier + // in a non-ObjC literal. + if (!IsObjCLiteral && CS.isObjCArg()) { + HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen); - if (Str[StrIdx-1] == '.') - Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type) - << E->getType() << E->getSourceRange(); - else - Diag(Loc, diag::warn_printf_asterisk_width_wrong_type) - << E->getType() << E->getSourceRange(); + // Continue checking the other format specifiers. + return true; + } - break; - } - } + if (!CS.consumesDataArgument()) { + // FIXME: Technically specifying a precision or field width here + // makes no sense. Worth issuing a warning at some point. + return true; + } - // Characters which can terminate a format conversion - // (e.g. "%d"). Characters that specify length modifiers or - // other flags are handled by the default case below. - // - // FIXME: additional checks will go into the following cases. - case 'i': - case 'd': - case 'o': - case 'u': - case 'x': - case 'X': - case 'D': - case 'O': - case 'U': - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - case 'a': - case 'A': - case 'c': - case 'C': - case 'S': - case 's': - case 'p': - ++numConversions; - CurrentState = state_OrdChr; - break; + ++NumConversions; - case 'm': - // FIXME: Warn in situations where this isn't supported! - CurrentState = state_OrdChr; - break; + // Are we using '%n'? Issue a warning about this being + // a possible security issue. + if (CS.getKind() == ConversionSpecifier::OutIntPtrArg) { + S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_write_back) + << getFormatSpecifierRange(startSpecifier, specifierLen); + // Continue checking the other format specifiers. + return true; + } - // CHECK: Are we using "%n"? Issue a warning. - case 'n': { - ++numConversions; - CurrentState = state_OrdChr; - SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, - LastConversionIdx); + if (CS.getKind() == ConversionSpecifier::VoidPtrArg) { + if (FS.getPrecision().getHowSpecified() != OptionalAmount::NotSpecified) + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_nonsensical_precision) + << CS.getCharacters() + << getFormatSpecifierRange(startSpecifier, specifierLen); + } + if (CS.getKind() == ConversionSpecifier::VoidPtrArg || + CS.getKind() == ConversionSpecifier::CStrArg) { + // FIXME: Instead of using "0", "+", etc., eventually get them from + // the FormatSpecifier. + if (FS.hasLeadingZeros()) + HandleFlags(FS, "0", CS.getCharacters(), startSpecifier, specifierLen); + if (FS.hasPlusPrefix()) + HandleFlags(FS, "+", CS.getCharacters(), startSpecifier, specifierLen); + if (FS.hasSpacePrefix()) + HandleFlags(FS, " ", CS.getCharacters(), startSpecifier, specifierLen); + } - Diag(Loc, diag::warn_printf_write_back)<<OrigFormatExpr->getSourceRange(); - break; - } + // The remaining checks depend on the data arguments. + if (HasVAListArg) + return true; - // Handle "%@" - case '@': - // %@ is allowed in ObjC format strings only. - if (ObjCFExpr != NULL) - CurrentState = state_OrdChr; - else { - // Issue a warning: invalid format conversion. - SourceLocation Loc = - getLocationOfStringLiteralByte(FExpr, LastConversionIdx); - - Diag(Loc, diag::warn_printf_invalid_conversion) - << std::string(Str+LastConversionIdx, - Str+std::min(LastConversionIdx+2, StrLen)) - << OrigFormatExpr->getSourceRange(); - } - ++numConversions; - break; + if (NumConversions > NumDataArgs) { + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_insufficient_data_args) + << getFormatSpecifierRange(startSpecifier, specifierLen); + // Don't do any more checking. + return false; + } - // Handle "%%" - case '%': - // Sanity check: Was the first "%" character the previous one? - // If not, we will assume that we have a malformed format - // conversion, and that the current "%" character is the start - // of a new conversion. - if (StrIdx - LastConversionIdx == 1) - CurrentState = state_OrdChr; - else { - // Issue a warning: invalid format conversion. - SourceLocation Loc = - getLocationOfStringLiteralByte(FExpr, LastConversionIdx); - - Diag(Loc, diag::warn_printf_invalid_conversion) - << std::string(Str+LastConversionIdx, Str+StrIdx) - << OrigFormatExpr->getSourceRange(); - - // This conversion is broken. Advance to the next format - // conversion. - LastConversionIdx = StrIdx; - ++numConversions; - } - break; + // Now type check the data expression that matches the + // format specifier. + const Expr *Ex = getDataArg(NumConversions); + const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context); + if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) { + // Check if we didn't match because of an implicit cast from a 'char' + // or 'short' to an 'int'. This is done because printf is a varargs + // function. + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex)) + if (ICE->getType() == S.Context.IntTy) + if (ATR.matchesType(S.Context, ICE->getSubExpr()->getType())) + return true; - default: - // This case catches all other characters: flags, widths, etc. - // We should eventually process those as well. - break; - } + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_conversion_argument_type_mismatch) + << ATR.getRepresentativeType(S.Context) << Ex->getType() + << getFormatSpecifierRange(startSpecifier, specifierLen) + << Ex->getSourceRange(); } - if (CurrentState == state_Conversion) { - // Issue a warning: invalid format conversion. - SourceLocation Loc = - getLocationOfStringLiteralByte(FExpr, LastConversionIdx); + return true; +} - Diag(Loc, diag::warn_printf_invalid_conversion) - << std::string(Str+LastConversionIdx, - Str+std::min(LastConversionIdx+2, StrLen)) - << OrigFormatExpr->getSourceRange(); +void CheckPrintfHandler::DoneProcessing() { + // Does the number of data arguments exceed the number of + // format conversions in the format string? + if (!HasVAListArg && NumConversions < NumDataArgs) + S.Diag(getDataArg(NumConversions+1)->getLocStart(), + diag::warn_printf_too_many_data_args) + << getFormatStringRange(); +} + +void Sema::CheckPrintfString(const StringLiteral *FExpr, + const Expr *OrigFormatExpr, + const CallExpr *TheCall, bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg) { + + // CHECK: is the format string a wide literal? + if (FExpr->isWide()) { + Diag(FExpr->getLocStart(), + diag::warn_printf_format_string_is_wide_literal) + << OrigFormatExpr->getSourceRange(); return; } - if (!HasVAListArg) { - // CHECK: Does the number of format conversions exceed the number - // of data arguments? - if (numConversions > numDataArgs) { - SourceLocation Loc = - getLocationOfStringLiteralByte(FExpr, LastConversionIdx); - - Diag(Loc, diag::warn_printf_insufficient_data_args) - << OrigFormatExpr->getSourceRange(); - } - // CHECK: Does the number of data arguments exceed the number of - // format conversions in the format string? - else if (numConversions < numDataArgs) - Diag(TheCall->getArg(format_idx+numConversions+1)->getLocStart(), - diag::warn_printf_too_many_data_args) - << OrigFormatExpr->getSourceRange(); + // Str - The format string. NOTE: this is NOT null-terminated! + const char *Str = FExpr->getStrData(); + + // CHECK: empty format string? + unsigned StrLen = FExpr->getByteLength(); + + if (StrLen == 0) { + Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string) + << OrigFormatExpr->getSourceRange(); + return; } + + CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, + TheCall->getNumArgs() - firstDataArg, + isa<ObjCStringLiteral>(OrigFormatExpr), Str, + HasVAListArg, TheCall, format_idx); + + if (!analyze_printf::ParseFormatString(H, Str, Str + StrLen)) + H.DoneProcessing(); } //===--- CHECK: Return Address of Stack Variable --------------------------===// @@ -1300,11 +1366,11 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, if (C->hasBlockDeclRefExprs()) Diag(C->getLocStart(), diag::err_ret_local_block) << C->getSourceRange(); - + if (AddrLabelExpr *ALE = dyn_cast<AddrLabelExpr>(RetValExp)) Diag(ALE->getLocStart(), diag::warn_ret_addr_label) << ALE->getSourceRange(); - + } else if (lhsType->isReferenceType()) { // Perform checking for stack values returned by reference. // Check for a reference to the stack @@ -1780,7 +1846,7 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { if (BO->getLHS()->getType()->isPointerType()) return IntRange::forType(C, E->getType()); // fallthrough - + default: break; } @@ -2221,7 +2287,7 @@ void Sema::CheckUnreachable(AnalysisContext &AC) { CFG *cfg = AC.getCFG(); if (cfg == 0) return; - + llvm::BitVector live(cfg->getNumBlockIDs()); // Mark all live things first. count = MarkLive(&cfg->getEntry(), live); @@ -2268,7 +2334,9 @@ void Sema::CheckUnreachable(AnalysisContext &AC) { CFGBlock &b = **I; if (!live[b.getBlockID()]) // Avoid excessive errors by marking everything reachable from here - lines.push_back(ErrLoc(MarkLiveTop(&b, live, Context.getSourceManager()), SourceRange(), SourceRange())); + lines.push_back(ErrLoc(MarkLiveTop(&b, live, + Context.getSourceManager()), + SourceRange(), SourceRange())); } } @@ -2418,17 +2486,19 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, // which this code would then warn about. if (getDiagnostics().hasErrorOccurred()) return; - + bool ReturnsVoid = false; bool HasNoReturn = false; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // If the result type of the function is a dependent type, we don't know - // whether it will be void or not, so don't - if (FD->getResultType()->isDependentType()) + // For function templates, class templates and member function templates + // we'll do the analysis at instantiation time. + if (FD->isDependentContext()) return; + if (FD->getResultType()->isVoidType()) ReturnsVoid = true; - if (FD->hasAttr<NoReturnAttr>()) + if (FD->hasAttr<NoReturnAttr>() || + FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) HasNoReturn = true; } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { if (MD->getResultType()->isVoidType()) @@ -2552,6 +2622,24 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { !Param->isImplicit() && !getLangOptions().CPlusPlus) Diag(Param->getLocation(), diag::err_parameter_name_omitted); + + // C99 6.7.5.3p12: + // If the function declarator is not part of a definition of that + // function, parameters may have incomplete type and may use the [*] + // notation in their sequences of declarator specifiers to specify + // variable length array types. + QualType PType = Param->getOriginalType(); + if (const ArrayType *AT = Context.getAsArrayType(PType)) { + if (AT->getSizeModifier() == ArrayType::Star) { + // FIXME: This diagnosic should point the the '[*]' if source-location + // information is added for it. + 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/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index fcd419bb10fb..a86294971861 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2196,13 +2196,15 @@ void Sema::CodeCompleteCase(Scope *S) { namespace { struct IsBetterOverloadCandidate { Sema &S; + SourceLocation Loc; public: - explicit IsBetterOverloadCandidate(Sema &S) : S(S) { } + explicit IsBetterOverloadCandidate(Sema &S, SourceLocation Loc) + : S(S), Loc(Loc) { } bool operator()(const OverloadCandidate &X, const OverloadCandidate &Y) const { - return S.isBetterOverloadCandidate(X, Y); + return S.isBetterOverloadCandidate(X, Y, Loc); } }; } @@ -2228,7 +2230,8 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, } // Build an overload candidate set based on the functions we find. - OverloadCandidateSet CandidateSet; + SourceLocation Loc = Fn->getExprLoc(); + OverloadCandidateSet CandidateSet(Loc); // FIXME: What if we're calling something that isn't a function declaration? // FIXME: What if we're calling a pseudo-destructor? @@ -2247,7 +2250,8 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, if (!FDecl->getType()->getAs<FunctionProtoType>()) Results.push_back(ResultCandidate(FDecl)); else - AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet, + // FIXME: access? + AddOverloadCandidate(FDecl, AS_none, Args, NumArgs, CandidateSet, false, false, /*PartialOverloading*/ true); } } @@ -2255,7 +2259,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, if (!CandidateSet.empty()) { // Sort the overload candidate set by placing the best overloads first. std::stable_sort(CandidateSet.begin(), CandidateSet.end(), - IsBetterOverloadCandidate(*this)); + IsBetterOverloadCandidate(*this, Loc)); // Add the remaining viable overload candidates as code-completion reslults. for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), @@ -2977,7 +2981,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. - DefaultFunctionArrayConversion(RecExpr); + DefaultFunctionArrayLvalueConversion(RecExpr); QualType ReceiverType = RecExpr->getType(); if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index fbe02894ace5..1fc08ce03197 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -14,7 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/AnalysisContext.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -135,6 +135,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: + Result.suppressDiagnostics(); return 0; case LookupResult::Ambiguous: @@ -509,9 +510,18 @@ static void RemoveUsingDecls(LookupResult &R) { } static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { + if (D->isInvalidDecl()) + return false; + if (D->isUsed() || D->hasAttr<UnusedAttr>()) return false; - + + // White-list anything that isn't a local variable. + if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) || + !D->getDeclContext()->isFunctionOrMethod()) + return false; + + // 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())) { @@ -523,9 +533,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { } } - return (isa<VarDecl>(D) && !isa<ParmVarDecl>(D) && - !isa<ImplicitParamDecl>(D) && - D->getDeclContext()->isFunctionOrMethod()); + return true; } void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { @@ -690,7 +698,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, FT->getArgType(i), /*TInfo=*/0, VarDecl::None, 0)); - New->setParams(Context, Params.data(), Params.size()); + New->setParams(Params.data(), Params.size()); } AddKnownFunctionAttributes(New); @@ -957,6 +965,44 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { return true; } + // If a function is first declared with a calling convention, but is + // later declared or defined without one, the second decl assumes the + // calling convention of the first. + // + // For the new decl, we have to look at the NON-canonical type to tell the + // difference between a function that really doesn't have a calling + // convention and one that is declared cdecl. That's because in + // canonicalization (see ASTContext.cpp), cdecl is canonicalized away + // because it is the default calling convention. + // + // Note also that we DO NOT return at this point, because we still have + // 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()); + New->setType(NewQType); + NewQType = Context.getCanonicalType(NewQType); + } else if (!Context.isSameCallConv(OldType->getCallConv(), + NewType->getCallConv())) { + // 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())); + Diag(Old->getLocation(), diag::note_previous_declaration); + return true; + } + + // FIXME: diagnose the other way around? + if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) { + NewQType = Context.getNoReturnType(NewQType); + New->setType(NewQType); + assert(NewQType.isCanonical()); + } + if (getLangOptions().CPlusPlus) { // (C++98 13.1p2): // Certain function declarations cannot be overloaded: @@ -1061,7 +1107,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Params.push_back(Param); } - New->setParams(Context, Params.data(), Params.size()); + New->setParams(Params.data(), Params.size()); } return MergeCompatibleFunctionDecls(New, Old); @@ -1297,6 +1343,18 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { Diag(Old->getLocation(), diag::note_previous_definition); } + // C++ doesn't have tentative definitions, so go right ahead and check here. + const VarDecl *Def; + if (getLangOptions().CPlusPlus && + New->isThisDeclarationADefinition() == VarDecl::Definition && + (Def = Old->getDefinition())) { + Diag(New->getLocation(), diag::err_redefinition) + << New->getDeclName(); + Diag(Def->getLocation(), diag::note_previous_definition); + New->setInvalidDecl(); + return; + } + // Keep a chain of previous declarations. New->setPreviousDeclaration(Old); @@ -1855,6 +1913,13 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, if (!DC->isDependentContext() && RequireCompleteDeclContext(D.getCXXScopeSpec())) return DeclPtrTy(); + + if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) { + Diag(D.getIdentifierLoc(), + diag::err_member_def_undefined_record) + << Name << DC << D.getCXXScopeSpec().getRange(); + D.setInvalidType(); + } LookupQualifiedName(Previous, DC); @@ -2322,7 +2387,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast<StringLiteral>(E); - NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getString())); + NewVD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString())); } // Don't consider existing declarations that are in a different @@ -2359,9 +2424,9 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // attributes declared post-definition are currently ignored if (Previous.isSingleResult()) { - const VarDecl *Def = 0; - VarDecl *PrevDecl = dyn_cast<VarDecl>(Previous.getFoundDecl()); - if (PrevDecl && PrevDecl->getDefinition(Def) && D.hasAttributes()) { + VarDecl *Def = dyn_cast<VarDecl>(Previous.getFoundDecl()); + if (Def && (Def = Def->getDefinition()) && + Def != NewVD && D.hasAttributes()) { Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition); Diag(Def->getLocation(), diag::note_previous_definition); } @@ -2675,7 +2740,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // (The parser checks for a return type and makes the declarator a // constructor if it has no return type). // must have an invalid constructor that has a return type - if (Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ + if (Name.getAsIdentifierInfo() && + Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); @@ -2783,6 +2849,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } + // C++ [dcl.fct.spec]p6: + // The explicit specifier shall be used only in the declaration of a + // constructor or conversion function within its class definition; see 12.3.1 + // and 12.3.2. + if (isExplicit && !NewFD->isInvalidDecl()) { + if (!CurContext->isRecord()) { + // 'explicit' was specified outside of the class. + Diag(D.getDeclSpec().getExplicitSpecLoc(), + diag::err_explicit_out_of_class) + << CodeModificationHint::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()); + } + } + // Filter out previous declarations that don't match the scope. FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); @@ -2822,7 +2910,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast<StringLiteral>(E); - NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getString())); + NewFD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString())); } // Copy the parameter declarations from the declarator D to the function @@ -2882,7 +2970,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, "Should not need args for typedef of non-prototype fn"); } // Finally, we know we have the right number of parameters, install them. - NewFD->setParams(Context, Params.data(), Params.size()); + NewFD->setParams(Params.data(), Params.size()); // If the declarator is a template-id, translate the parser's template // argument list into our AST format. @@ -2950,7 +3038,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { // Fake up an access specifier if it's supposed to be a class member. - if (isa<CXXRecordDecl>(NewFD->getDeclContext())) + if (!Redeclaration && isa<CXXRecordDecl>(NewFD->getDeclContext())) NewFD->setAccess(AS_public); // An out-of-line member function declaration must also be a @@ -3041,6 +3129,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate) return FunctionTemplate; + + // Keep track of static, non-inlined function definitions that + // have not been used. We will warn later. + // FIXME: Also include static functions declared but not defined. + if (!NewFD->isInvalidDecl() && IsFunctionDefinition + && !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage + && !NewFD->isUsed()) + UnusedStaticFuncs.push_back(NewFD); + return NewFD; } @@ -3412,8 +3509,8 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { AbstractVariableType)) VDecl->setInvalidDecl(); - const VarDecl *Def = 0; - if (VDecl->getDefinition(Def)) { + const VarDecl *Def; + if ((Def = VDecl->getDefinition()) && Def != VDecl) { Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); Diag(Def->getLocation(), diag::note_previous_definition); @@ -3473,7 +3570,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { // }; // Attach the initializer - VDecl->setInit(Context, Init); + VDecl->setInit(Init); // C++ [class.mem]p4: // A member-declarator can contain a constant-initializer only @@ -3545,23 +3642,15 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { Init = MaybeCreateCXXExprWithTemporaries(Init); // Attach the initializer to the decl. - VDecl->setInit(Context, Init); - - // If the previous declaration of VDecl was a tentative definition, - // remove it from the set of tentative definitions. - if (VDecl->getPreviousDeclaration() && - VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) { - bool Deleted = TentativeDefinitions.erase(VDecl->getDeclName()); - assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted; - } + VDecl->setInit(Init); if (getLangOptions().CPlusPlus) { // Make sure we mark the destructor as used if necessary. QualType InitType = VDecl->getType(); while (const ArrayType *Array = Context.getAsArrayType(InitType)) InitType = Context.getBaseElementType(Array); - if (InitType->isRecordType()) - FinalizeVarWithDestructor(VDecl, InitType); + if (const RecordType *Record = InitType->getAs<RecordType>()) + FinalizeVarWithDestructor(VDecl, Record); } return; @@ -3578,136 +3667,140 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) { QualType Type = Var->getType(); - // Record tentative definitions. - if (Var->isTentativeDefinition(Context)) { - std::pair<llvm::DenseMap<DeclarationName, VarDecl *>::iterator, bool> - InsertPair = - TentativeDefinitions.insert(std::make_pair(Var->getDeclName(), Var)); + // C++0x [dcl.spec.auto]p3 + if (TypeContainsUndeducedAuto) { + Diag(Var->getLocation(), diag::err_auto_var_requires_init) + << Var->getDeclName() << Type; + Var->setInvalidDecl(); + return; + } + + switch (Var->isThisDeclarationADefinition()) { + case VarDecl::Definition: + if (!Var->isStaticDataMember() || !Var->getAnyInitializer()) + break; - // Keep the latest definition in the map. If we see 'int i; int i;' we - // want the second one in the map. - InsertPair.first->second = Var; + // We have an out-of-line definition of a static data member + // that has an in-class initializer, so we type-check this like + // a declaration. + // + // Fall through + + case VarDecl::DeclarationOnly: + // It's only a declaration. + + // Block scope. C99 6.7p7: If an identifier for an object is + // declared with no linkage (C99 6.2.2p6), the type for the + // object shall be complete. + if (!Type->isDependentType() && Var->isBlockVarDecl() && + !Var->getLinkage() && !Var->isInvalidDecl() && + RequireCompleteType(Var->getLocation(), Type, + diag::err_typecheck_decl_incomplete_type)) + Var->setInvalidDecl(); - // However, for the list, we don't care about the order, just make sure - // that there are no dupes for a given declaration name. - if (InsertPair.second) - TentativeDefinitionList.push_back(Var->getDeclName()); + // Make sure that the type is not abstract. + if (!Type->isDependentType() && !Var->isInvalidDecl() && + RequireNonAbstractType(Var->getLocation(), Type, + diag::err_abstract_type_in_decl, + AbstractVariableType)) + Var->setInvalidDecl(); + return; + + case VarDecl::TentativeDefinition: + // File scope. C99 6.9.2p2: A declaration of an identifier for an + // object that has file scope without an initializer, and without a + // storage-class specifier or with the storage-class specifier "static", + // constitutes a tentative definition. Note: A tentative definition with + // external linkage is valid (C99 6.2.2p5). + if (!Var->isInvalidDecl()) { + if (const IncompleteArrayType *ArrayT + = Context.getAsIncompleteArrayType(Type)) { + if (RequireCompleteType(Var->getLocation(), + ArrayT->getElementType(), + diag::err_illegal_decl_array_incomplete_type)) + Var->setInvalidDecl(); + } else if (Var->getStorageClass() == VarDecl::Static) { + // C99 6.9.2p3: If the declaration of an identifier for an object is + // a tentative definition and has internal linkage (C99 6.2.2p3), the + // declared type shall not be an incomplete type. + // NOTE: code such as the following + // static struct s; + // struct s { int a; }; + // is accepted by gcc. Hence here we issue a warning instead of + // an error and we do not invalidate the static declaration. + // NOTE: to avoid multiple warnings, only check the first declaration. + if (Var->getPreviousDeclaration() == 0) + RequireCompleteType(Var->getLocation(), Type, + diag::ext_typecheck_decl_incomplete_type); + } + } + + // Record the tentative definition; we're done. + if (!Var->isInvalidDecl()) + TentativeDefinitions.push_back(Var); + return; } - // C++ [dcl.init.ref]p3: - // The initializer can be omitted for a reference only in a - // parameter declaration (8.3.5), in the declaration of a - // function return type, in the declaration of a class member - // within its class declaration (9.2), and where the extern - // specifier is explicitly used. - if (Type->isReferenceType() && !Var->hasExternalStorage()) { - Diag(Var->getLocation(), diag::err_reference_var_requires_init) - << Var->getDeclName() - << SourceRange(Var->getLocation(), Var->getLocation()); + // Provide a specific diagnostic for uninitialized variable + // definitions with incomplete array type. + if (Type->isIncompleteArrayType()) { + Diag(Var->getLocation(), + diag::err_typecheck_incomplete_array_needs_initializer); Var->setInvalidDecl(); return; } - // C++0x [dcl.spec.auto]p3 - if (TypeContainsUndeducedAuto) { - Diag(Var->getLocation(), diag::err_auto_var_requires_init) - << Var->getDeclName() << Type; + // Provide a specific diagnostic for uninitialized variable + // definitions with reference type. + if (Type->isReferenceType()) { + Diag(Var->getLocation(), diag::err_reference_var_requires_init) + << Var->getDeclName() + << SourceRange(Var->getLocation(), Var->getLocation()); + Var->setInvalidDecl(); + return; + } + + // Do not attempt to type-check the default initializer for a + // variable with dependent type. + if (Type->isDependentType()) + return; + + if (Var->isInvalidDecl()) + return; + + if (RequireCompleteType(Var->getLocation(), + Context.getBaseElementType(Type), + diag::err_typecheck_decl_incomplete_type)) { Var->setInvalidDecl(); return; } - // An array without size is an incomplete type, and there are no special - // rules in C++ to make such a definition acceptable. - if (getLangOptions().CPlusPlus && Type->isIncompleteArrayType() && - !Var->hasExternalStorage()) { - Diag(Var->getLocation(), - diag::err_typecheck_incomplete_array_needs_initializer); + // The variable can not have an abstract class type. + if (RequireNonAbstractType(Var->getLocation(), Type, + diag::err_abstract_type_in_decl, + AbstractVariableType)) { Var->setInvalidDecl(); return; } - // C++ [temp.expl.spec]p15: - // An explicit specialization of a static data member of a template is a - // definition if the declaration includes an initializer; otherwise, it - // is a declaration. - if (Var->isStaticDataMember() && - Var->getInstantiatedFromStaticDataMember() && - Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) - return; + InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); + InitializationKind Kind + = InitializationKind::CreateDefault(Var->getLocation()); - // C++ [dcl.init]p9: - // If no initializer is specified for an object, and the object - // is of (possibly cv-qualified) non-POD class type (or array - // thereof), the object shall be default-initialized; if the - // object is of const-qualified type, the underlying class type - // shall have a user-declared default constructor. - // - // FIXME: Diagnose the "user-declared default constructor" bit. - if (getLangOptions().CPlusPlus) { - QualType InitType = Type; - if (const ArrayType *Array = Context.getAsArrayType(Type)) - InitType = Context.getBaseElementType(Array); - if ((!Var->hasExternalStorage() && !Var->isExternC()) && - InitType->isRecordType() && !InitType->isDependentType()) { - if (!RequireCompleteType(Var->getLocation(), InitType, - diag::err_invalid_incomplete_type_use)) { - InitializedEntity Entity - = InitializedEntity::InitializeVariable(Var); - InitializationKind Kind - = InitializationKind::CreateDefault(Var->getLocation()); - - InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, 0, 0)); - if (Init.isInvalid()) - Var->setInvalidDecl(); - else { - Var->setInit(Context, - MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>())); - FinalizeVarWithDestructor(Var, InitType); - } - } else { - Var->setInvalidDecl(); - } - } + InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); + OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, 0, 0)); + if (Init.isInvalid()) + Var->setInvalidDecl(); + else { + if (Init.get()) + Var->setInit(MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>())); - // The variable can not have an abstract class type. - if (RequireNonAbstractType(Var->getLocation(), Type, - diag::err_abstract_type_in_decl, - AbstractVariableType)) - Var->setInvalidDecl(); + if (getLangOptions().CPlusPlus) + if (const RecordType *Record + = Context.getBaseElementType(Type)->getAs<RecordType>()) + FinalizeVarWithDestructor(Var, Record); } - -#if 0 - // FIXME: Temporarily disabled because we are not properly parsing - // linkage specifications on declarations, e.g., - // - // extern "C" const CGPoint CGPointerZero; - // - // C++ [dcl.init]p9: - // - // If no initializer is specified for an object, and the - // object is of (possibly cv-qualified) non-POD class type (or - // array thereof), the object shall be default-initialized; if - // the object is of const-qualified type, the underlying class - // type shall have a user-declared default - // constructor. Otherwise, if no initializer is specified for - // an object, the object and its subobjects, if any, have an - // indeterminate initial value; if the object or any of its - // subobjects are of const-qualified type, the program is - // ill-formed. - // - // This isn't technically an error in C, so we don't diagnose it. - // - // FIXME: Actually perform the POD/user-defined default - // constructor check. - if (getLangOptions().CPlusPlus && - Context.getCanonicalType(Type).isConstQualified() && - !Var->hasExternalStorage()) - Diag(Var->getLocation(), diag::err_const_var_requires_init) - << Var->getName() - << SourceRange(Var->getLocation(), Var->getLocation()); -#endif } } @@ -3723,77 +3816,6 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, if (Decl *D = Group[i].getAs<Decl>()) Decls.push_back(D); - // Perform semantic analysis that depends on having fully processed both - // the declarator and initializer. - for (unsigned i = 0, e = Decls.size(); i != e; ++i) { - VarDecl *IDecl = dyn_cast<VarDecl>(Decls[i]); - if (!IDecl) - continue; - QualType T = IDecl->getType(); - - // Block scope. C99 6.7p7: If an identifier for an object is declared with - // no linkage (C99 6.2.2p6), the type for the object shall be complete... - if (IDecl->isBlockVarDecl() && !IDecl->hasExternalStorage()) { - if (T->isDependentType()) { - // If T is dependent, we should not require a complete type. - // (RequireCompleteType shouldn't be called with dependent types.) - // But we still can at least check if we've got an array of unspecified - // size without an initializer. - if (!IDecl->isInvalidDecl() && T->isIncompleteArrayType() && - !IDecl->getInit()) { - Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type) - << T; - IDecl->setInvalidDecl(); - } - } else if (!IDecl->isInvalidDecl()) { - // If T is an incomplete array type with an initializer list that is - // dependent on something, its size has not been fixed. We could attempt - // to fix the size for such arrays, but we would still have to check - // here for initializers containing a C++0x vararg expansion, e.g. - // template <typename... Args> void f(Args... args) { - // int vals[] = { args }; - // } - const IncompleteArrayType *IAT = Context.getAsIncompleteArrayType(T); - Expr *Init = IDecl->getInit(); - if (IAT && Init && - (Init->isTypeDependent() || Init->isValueDependent())) { - // Check that the member type of the array is complete, at least. - if (RequireCompleteType(IDecl->getLocation(), IAT->getElementType(), - diag::err_typecheck_decl_incomplete_type)) - IDecl->setInvalidDecl(); - } else if (RequireCompleteType(IDecl->getLocation(), T, - diag::err_typecheck_decl_incomplete_type)) - IDecl->setInvalidDecl(); - } - } - // File scope. C99 6.9.2p2: A declaration of an identifier for an - // object that has file scope without an initializer, and without a - // storage-class specifier or with the storage-class specifier "static", - // constitutes a tentative definition. Note: A tentative definition with - // external linkage is valid (C99 6.2.2p5). - if (IDecl->isTentativeDefinition(Context) && !IDecl->isInvalidDecl()) { - if (const IncompleteArrayType *ArrayT - = Context.getAsIncompleteArrayType(T)) { - if (RequireCompleteType(IDecl->getLocation(), - ArrayT->getElementType(), - diag::err_illegal_decl_array_incomplete_type)) - IDecl->setInvalidDecl(); - } else if (IDecl->getStorageClass() == VarDecl::Static) { - // C99 6.9.2p3: If the declaration of an identifier for an object is - // a tentative definition and has internal linkage (C99 6.2.2p3), the - // declared type shall not be an incomplete type. - // NOTE: code such as the following - // static struct s; - // struct s { int a; }; - // is accepted by gcc. Hence here we issue a warning instead of - // an error and we do not invalidate the static declaration. - // NOTE: to avoid multiple warnings, only check the first declaration. - if (IDecl->getPreviousDeclaration() == 0) - RequireCompleteType(IDecl->getLocation(), T, - diag::ext_typecheck_decl_incomplete_type); - } - } - } return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Decls.data(), Decls.size())); } @@ -3853,6 +3875,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Recover by removing the name II = 0; D.SetIdentifier(0, D.getIdentifierLoc()); + D.setInvalidType(true); } } } @@ -3919,6 +3942,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { return DeclPtrTy::make(New); } +void Sema::ActOnObjCCatchParam(DeclPtrTy D) { + ParmVarDecl *Param = cast<ParmVarDecl>(D.getAs<Decl>()); + Param->setDeclContext(CurContext); +} + void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls) { assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && @@ -4297,8 +4325,8 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { bool HasVAListArg; if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) { if (!FD->getAttr<FormatAttr>()) - FD->addAttr(::new (Context) FormatAttr("printf", FormatIdx + 1, - HasVAListArg ? 0 : FormatIdx + 2)); + FD->addAttr(::new (Context) FormatAttr(Context, "printf", FormatIdx+1, + HasVAListArg ? 0 : FormatIdx+2)); } // Mark const if we don't care about errno and that is the only @@ -4311,7 +4339,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { } if (Context.BuiltinInfo.isNoReturn(BuiltinID)) - FD->addAttr(::new (Context) NoReturnAttr()); + FD->setType(Context.getNoReturnType(FD->getType())); if (Context.BuiltinInfo.isNoThrow(BuiltinID)) FD->addAttr(::new (Context) NoThrowAttr()); if (Context.BuiltinInfo.isConst(BuiltinID)) @@ -4335,15 +4363,15 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { // FIXME: NSLog and NSLogv should be target specific if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) { // FIXME: We known better than our headers. - const_cast<FormatAttr *>(Format)->setType("printf"); + const_cast<FormatAttr *>(Format)->setType(Context, "printf"); } else - FD->addAttr(::new (Context) FormatAttr("printf", 1, + FD->addAttr(::new (Context) FormatAttr(Context, "printf", 1, Name->isStr("NSLogv") ? 0 : 2)); } else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) { // FIXME: asprintf and vasprintf aren't C99 functions. Should they be // target-specific builtins, perhaps? if (!FD->getAttr<FormatAttr>()) - FD->addAttr(::new (Context) FormatAttr("printf", 2, + FD->addAttr(::new (Context) FormatAttr(Context, "printf", 2, Name->isStr("vasprintf") ? 0 : 3)); } } @@ -4614,7 +4642,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // Diagnose attempts to redefine a tag. if (TUK == TUK_Definition) { - if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) { + if (TagDecl *Def = PrevTagDecl->getDefinition()) { // If we're defining a specialization and the previous definition // is from an implicit instantiation, don't emit an error // here; we'll catch this in the general case below. @@ -4927,9 +4955,17 @@ RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record, if (Record->isDependentContext() || !Record->isDefinition()) return; - if (Record->isDynamicClass() && !S.Context.getKeyFunction(Record)) - S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, Loc)); + if (Record->isDynamicClass()) { + const CXXMethodDecl *KeyFunction = S.Context.getKeyFunction(Record); + if (!KeyFunction) + S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, + Loc)); + + if ((!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined())) + && Record->getLinkage() == ExternalLinkage) + S.Diag(Record->getLocation(), diag::warn_weak_vtable) << Record; + } for (DeclContext::decl_iterator D = Record->decls_begin(), DEnd = Record->decls_end(); D != DEnd; ++D) { @@ -5156,7 +5192,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, NewFD->setInvalidDecl(); } - if (getLangOptions().CPlusPlus) { + if (!InvalidDecl && getLangOptions().CPlusPlus) { CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record); if (!T->isPODType()) @@ -5584,7 +5620,7 @@ void Sema::ActOnFields(Scope* S, // Okay, we successfully defined 'Record'. if (Record) { - Record->completeDefinition(Context); + Record->completeDefinition(); } else { ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(RecFields.data()); @@ -5628,6 +5664,45 @@ void Sema::ActOnFields(Scope* S, ProcessDeclAttributeList(S, Record, Attr); } +/// \brief Determine whether the given integral value is representable within +/// the given type T. +static bool isRepresentableIntegerValue(ASTContext &Context, + llvm::APSInt &Value, + QualType T) { + assert(T->isIntegralType() && "Integral type required!"); + unsigned BitWidth = Context.getTypeSize(T); + + if (Value.isUnsigned() || Value.isNonNegative()) + return Value.getActiveBits() < BitWidth; + + return Value.getMinSignedBits() <= BitWidth; +} + +// \brief Given an integral type, return the next larger integral type +// (or a NULL type of no such type exists). +static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) { + // FIXME: Int128/UInt128 support, which also needs to be introduced into + // enum checking below. + assert(T->isIntegralType() && "Integral type required!"); + const unsigned NumTypes = 4; + QualType SignedIntegralTypes[NumTypes] = { + Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy + }; + QualType UnsignedIntegralTypes[NumTypes] = { + Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy, + Context.UnsignedLongLongTy + }; + + unsigned BitWidth = Context.getTypeSize(T); + QualType *Types = T->isSignedIntegerType()? SignedIntegralTypes + : UnsignedIntegralTypes; + for (unsigned I = 0; I != NumTypes; ++I) + if (Context.getTypeSize(Types[I]) > BitWidth) + return Types[I]; + + return QualType(); +} + EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, @@ -5635,24 +5710,45 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, ExprArg val) { Expr *Val = (Expr *)val.get(); - llvm::APSInt EnumVal(32); + unsigned IntWidth = Context.Target.getIntWidth(); + llvm::APSInt EnumVal(IntWidth); QualType EltTy; if (Val) { if (Enum->isDependentType()) EltTy = Context.DependentTy; else { - // Make sure to promote the operand type to int. - UsualUnaryConversions(Val); - if (Val != val.get()) { - val.release(); - val = Val; - } - // C99 6.7.2.2p2: Make sure we have an integer constant expression. SourceLocation ExpLoc; if (VerifyIntegerConstantExpression(Val, &EnumVal)) { Val = 0; - } else { + } else { + if (!getLangOptions().CPlusPlus) { + // C99 6.7.2.2p2: + // The expression that defines the value of an enumeration constant + // shall be an integer constant expression that has a value + // representable as an int. + + // Complain if the value is not representable in an int. + if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy)) + Diag(IdLoc, diag::ext_enum_value_not_int) + << EnumVal.toString(10) << Val->getSourceRange() + << EnumVal.isNonNegative(); + else if (!Context.hasSameType(Val->getType(), Context.IntTy)) { + // Force the type of the expression to 'int'. + ImpCastExprToType(Val, Context.IntTy, CastExpr::CK_IntegralCast); + + if (Val != val.get()) { + val.release(); + val = Val; + } + } + } + + // C++0x [dcl.enum]p5: + // If the underlying type is not fixed, the type of each enumerator + // is the type of its initializing value: + // - If an initializer is specified for an enumerator, the + // initializing value has the same type as the expression. EltTy = Val->getType(); } } @@ -5661,25 +5757,76 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (!Val) { if (Enum->isDependentType()) EltTy = Context.DependentTy; - else if (LastEnumConst) { + else if (!LastEnumConst) { + // C++0x [dcl.enum]p5: + // If the underlying type is not fixed, the type of each enumerator + // is the type of its initializing value: + // - If no initializer is specified for the first enumerator, the + // initializing value has an unspecified integral type. + // + // GCC uses 'int' for its unspecified integral type, as does + // C99 6.7.2.2p3. + EltTy = Context.IntTy; + } else { // Assign the last value + 1. EnumVal = LastEnumConst->getInitVal(); ++EnumVal; + EltTy = LastEnumConst->getType(); // Check for overflow on increment. - if (EnumVal < LastEnumConst->getInitVal()) - Diag(IdLoc, diag::warn_enum_value_overflow); - - EltTy = LastEnumConst->getType(); - } else { - // First value, set to zero. - EltTy = Context.IntTy; - EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy))); - EnumVal.setIsSigned(true); + if (EnumVal < LastEnumConst->getInitVal()) { + // C++0x [dcl.enum]p5: + // If the underlying type is not fixed, the type of each enumerator + // is the type of its initializing value: + // + // - Otherwise the type of the initializing value is the same as + // the type of the initializing value of the preceding enumerator + // unless the incremented value is not representable in that type, + // in which case the type is an unspecified integral type + // sufficient to contain the incremented value. If no such type + // exists, the program is ill-formed. + QualType T = getNextLargerIntegralType(Context, EltTy); + if (T.isNull()) { + // There is no integral type larger enough to represent this + // value. Complain, then allow the value to wrap around. + EnumVal = LastEnumConst->getInitVal(); + EnumVal.zext(EnumVal.getBitWidth() * 2); + Diag(IdLoc, diag::warn_enumerator_too_large) + << EnumVal.toString(10); + } else { + EltTy = T; + } + + // Retrieve the last enumerator's value, extent that type to the + // type that is supposed to be large enough to represent the incremented + // value, then increment. + EnumVal = LastEnumConst->getInitVal(); + EnumVal.setIsSigned(EltTy->isSignedIntegerType()); + EnumVal.zextOrTrunc(Context.getTypeSize(EltTy)); + ++EnumVal; + + // If we're not in C++, diagnose the overflow of enumerator values, + // which in C99 means that the enumerator value is not representable in + // an int (C99 6.7.2.2p2). However, we support GCC's extension that + // permits enumerator values that are representable in some larger + // integral type. + if (!getLangOptions().CPlusPlus && !T.isNull()) + Diag(IdLoc, diag::warn_enum_value_overflow); + } else if (!getLangOptions().CPlusPlus && + !isRepresentableIntegerValue(Context, EnumVal, EltTy)) { + // Enforce C99 6.7.2.2p2 even when we compute the next value. + Diag(IdLoc, diag::ext_enum_value_not_int) + << EnumVal.toString(10) << 1; + } } } - assert(!EltTy.isNull() && "Enum constant with NULL type"); + if (!Enum->isDependentType()) { + // Make the enumerator value match the signedness and size of the + // enumerator's type. + EnumVal.zextOrTrunc(Context.getTypeSize(EltTy)); + EnumVal.setIsSigned(EltTy->isSignedIntegerType()); + } val.release(); return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, @@ -5759,7 +5906,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(EnumType); } - Enum->completeDefinition(Context, Context.DependentTy, Context.DependentTy); + Enum->completeDefinition(Context.DependentTy, Context.DependentTy); return; } @@ -5783,18 +5930,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>()); if (!ECD) continue; // Already issued a diagnostic. - // If the enum value doesn't fit in an int, emit an extension warning. const llvm::APSInt &InitVal = ECD->getInitVal(); - assert(InitVal.getBitWidth() >= IntWidth && - "Should have promoted value to int"); - if (!getLangOptions().CPlusPlus && InitVal.getBitWidth() > IntWidth) { - llvm::APSInt V(InitVal); - V.trunc(IntWidth); - V.extend(InitVal.getBitWidth()); - if (V != InitVal) - Diag(ECD->getLocation(), diag::ext_enum_value_not_int) - << InitVal.toString(10); - } // Keep track of the size of positive and negative values. if (InitVal.isUnsigned() || InitVal.isNonNegative()) @@ -5856,8 +5992,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType); } else { - // If there is no negative value, figure out which of uint, ulong, ulonglong - // fits. + // If there is no negative value, figure out the smallest type that fits + // all of the enumerator values. // If it's packed, check also if it fits a char or a short. if (Packed && NumPositiveBits <= CharWidth) { BestType = Context.UnsignedCharTy; @@ -5870,30 +6006,26 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } else if (NumPositiveBits <= IntWidth) { BestType = Context.UnsignedIntTy; BestWidth = IntWidth; - BestPromotionType = (NumPositiveBits == BestWidth - ? Context.UnsignedIntTy : Context.IntTy); + BestPromotionType + = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus) + ? Context.UnsignedIntTy : Context.IntTy; } else if (NumPositiveBits <= (BestWidth = Context.Target.getLongWidth())) { BestType = Context.UnsignedLongTy; - BestPromotionType = (NumPositiveBits == BestWidth - ? Context.UnsignedLongTy : Context.LongTy); + BestPromotionType + = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus) + ? Context.UnsignedLongTy : Context.LongTy; } else { BestWidth = Context.Target.getLongLongWidth(); assert(NumPositiveBits <= BestWidth && "How could an initializer get larger than ULL?"); BestType = Context.UnsignedLongLongTy; - BestPromotionType = (NumPositiveBits == BestWidth - ? Context.UnsignedLongLongTy : Context.LongLongTy); + BestPromotionType + = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus) + ? Context.UnsignedLongLongTy : Context.LongLongTy; } } - // If we're in C and the promotion type is larger than an int, just - // use the underlying type, which is generally the unsigned integer - // type of the same rank as the promotion type. This is how the gcc - // extension works. - if (!getLangOptions().CPlusPlus && BestPromotionType != Context.IntTy) - BestPromotionType = BestType; - // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. for (unsigned i = 0; i != NumElements; ++i) { @@ -5906,23 +6038,17 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // enumerator value fits in an int, type it as an int, otherwise type it the // same as the enumerator decl itself. This means that in "enum { X = 1U }" // that X has type 'int', not 'unsigned'. - if (!getLangOptions().CPlusPlus && ECD->getType() == Context.IntTy) - continue; // Determine whether the value fits into an int. llvm::APSInt InitVal = ECD->getInitVal(); - bool FitsInInt; - if (InitVal.isUnsigned() || !InitVal.isNegative()) - FitsInInt = InitVal.getActiveBits() < IntWidth; - else - FitsInInt = InitVal.getMinSignedBits() <= IntWidth; // If it fits into an integer type, force it. Otherwise force it to match // the enum decl type. QualType NewTy; unsigned NewWidth; bool NewSign; - if (FitsInInt && !getLangOptions().CPlusPlus) { + if (!getLangOptions().CPlusPlus && + isRepresentableIntegerValue(Context, InitVal, Context.IntTy)) { NewTy = Context.IntTy; NewWidth = IntWidth; NewSign = true; @@ -5960,7 +6086,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(NewTy); } - Enum->completeDefinition(Context, BestType, BestPromotionType); + Enum->completeDefinition(BestType, BestPromotionType); } Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 1a12208e5a94..cba1e9e1cd50 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -307,7 +307,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { unsigned* start = &NonNullArgs[0]; unsigned size = NonNullArgs.size(); std::sort(start, start + size); - d->addAttr(::new (S.Context) NonNullAttr(start, size)); + d->addAttr(::new (S.Context) NonNullAttr(S.Context, start, size)); } static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -329,7 +329,7 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { // FIXME: check if target symbol exists in current file - d->addAttr(::new (S.Context) AliasAttr(Str->getString())); + d->addAttr(::new (S.Context) AliasAttr(S.Context, Str->getString())); } static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, @@ -391,6 +391,11 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, } static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Don't apply as a decl attribute to ValueDecl. + // FIXME: probably ought to diagnose this. + if (isa<ValueDecl>(d)) + return; + if (HandleCommonNoReturnAttr(d, Attr, S)) d->addAttr(::new (S.Context) NoReturnAttr()); } @@ -404,7 +409,7 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << 8; /*function, method, or parameter*/ + << Attr.getName() << 8 /*function, method, or parameter*/; return; } // FIXME: Actually store the attribute on the declaration @@ -542,17 +547,16 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - const char *TypeStr = Str->getStrData(); - unsigned TypeLen = Str->getByteLength(); + llvm::StringRef TypeStr = Str->getString(); VisibilityAttr::VisibilityTypes type; - if (TypeLen == 7 && !memcmp(TypeStr, "default", 7)) + if (TypeStr == "default") type = VisibilityAttr::DefaultVisibility; - else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6)) + else if (TypeStr == "hidden") type = VisibilityAttr::HiddenVisibility; - else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8)) + else if (TypeStr == "internal") type = VisibilityAttr::HiddenVisibility; // FIXME - else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9)) + else if (TypeStr == "protected") type = VisibilityAttr::ProtectedVisibility; else { S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr; @@ -938,105 +942,9 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - D->addAttr(::new (S.Context) SectionAttr(SE->getString())); -} - -static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // Attribute has no arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - // Attribute can be applied only to functions. - if (!isa<FunctionDecl>(d)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; - return; - } - - // cdecl and fastcall attributes are mutually incompatible. - if (d->getAttr<FastCallAttr>()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << "cdecl" << "fastcall"; - return; - } - - // cdecl and stdcall attributes are mutually incompatible. - if (d->getAttr<StdCallAttr>()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << "cdecl" << "stdcall"; - return; - } - - d->addAttr(::new (S.Context) CDeclAttr()); -} - - -static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // Attribute has no arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - // Attribute can be applied only to functions. - if (!isa<FunctionDecl>(d)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; - return; - } - - // stdcall and fastcall attributes are mutually incompatible. - if (d->getAttr<FastCallAttr>()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << "stdcall" << "fastcall"; - return; - } - - d->addAttr(::new (S.Context) StdCallAttr()); -} - -/// Diagnose the use of a non-standard calling convention on the given -/// function. -static void DiagnoseCConv(FunctionDecl *D, const char *CConv, - SourceLocation Loc, Sema &S) { - if (!D->hasPrototype()) { - S.Diag(Loc, diag::err_cconv_knr) << CConv; - return; - } - - const FunctionProtoType *T = D->getType()->getAs<FunctionProtoType>(); - if (T->isVariadic()) { - S.Diag(Loc, diag::err_cconv_varargs) << CConv; - return; - } + D->addAttr(::new (S.Context) SectionAttr(S.Context, SE->getString())); } -static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // Attribute has no arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - if (!isa<FunctionDecl>(d)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; - return; - } - - DiagnoseCConv(cast<FunctionDecl>(d), "fastcall", Attr.getLoc(), S); - - // stdcall and fastcall attributes are mutually incompatible. - if (d->getAttr<StdCallAttr>()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << "fastcall" << "stdcall"; - return; - } - - d->addAttr(::new (S.Context) FastCallAttr()); -} static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. @@ -1349,7 +1257,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) FormatAttr(Format, Idx.getZExtValue(), + d->addAttr(::new (S.Context) FormatAttr(S.Context, Format, Idx.getZExtValue(), FirstArg.getZExtValue())); } @@ -1435,7 +1343,7 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate"; return; } - d->addAttr(::new (S.Context) AnnotateAttr(SE->getString())); + d->addAttr(::new (S.Context) AnnotateAttr(S.Context, SE->getString())); } static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1608,9 +1516,15 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { if (!IntegerMode) NewTy = S.Context.DoubleTy; else if (OldTy->isSignedIntegerType()) - NewTy = S.Context.LongLongTy; + if (S.Context.Target.getLongWidth() == 64) + NewTy = S.Context.LongTy; + else + NewTy = S.Context.LongLongTy; else - NewTy = S.Context.UnsignedLongLongTy; + if (S.Context.Target.getLongWidth() == 64) + NewTy = S.Context.UnsignedLongTy; + else + NewTy = S.Context.UnsignedLongLongTy; break; case 96: NewTy = S.Context.LongDoubleTy; @@ -1903,7 +1817,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break; case AttributeList::AT_carries_dependency: HandleDependencyAttr (D, Attr, S); break; - case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break; case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break; case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break; case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break; @@ -1912,7 +1825,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_ext_vector_type: HandleExtVectorTypeAttr(scope, D, Attr, S); break; - case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break; case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break; case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break; case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break; @@ -1935,7 +1847,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break; case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break; - case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break; case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break; case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; @@ -1964,6 +1875,11 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_no_instrument_function: // Interacts with -pg. // Just ignore break; + case AttributeList::AT_stdcall: + case AttributeList::AT_cdecl: + case AttributeList::AT_fastcall: + // These are all treated as type attributes. + break; default: // Ask target about the attribute. const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); @@ -2008,7 +1924,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...)) IdentifierInfo *NDId = ND->getIdentifier(); NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias()); - NewD->addAttr(::new (Context) AliasAttr(NDId->getName())); + NewD->addAttr(::new (Context) AliasAttr(Context, NDId->getName())); NewD->addAttr(::new (Context) WeakAttr()); WeakTopLevelDecl.push_back(NewD); // FIXME: "hideous" code from Sema::LazilyCreateBuiltin @@ -2062,48 +1978,71 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { /// on the warning stack. Action::ParsingDeclStackState Sema::PushParsingDeclaration() { ParsingDeclDepth++; - return (ParsingDeclStackState) DelayedDeprecationWarnings.size(); -} - -static bool isDeclDeprecated(Decl *D) { - do { - if (D->hasAttr<DeprecatedAttr>()) - return true; - } while ((D = cast_or_null<Decl>(D->getDeclContext()))); - return false; + return (ParsingDeclStackState) DelayedDiagnostics.size(); } void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack"); ParsingDeclDepth--; - if (DelayedDeprecationWarnings.empty()) + if (DelayedDiagnostics.empty()) return; unsigned SavedIndex = (unsigned) S; - assert(SavedIndex <= DelayedDeprecationWarnings.size() && + assert(SavedIndex <= DelayedDiagnostics.size() && "saved index is out of bounds"); - if (Ctx && !isDeclDeprecated(Ctx.getAs<Decl>())) { - for (unsigned I = 0, E = DelayedDeprecationWarnings.size(); I != E; ++I) { - SourceLocation Loc = DelayedDeprecationWarnings[I].first; - NamedDecl *&ND = DelayedDeprecationWarnings[I].second; - if (ND) { - Diag(Loc, diag::warn_deprecated) << ND->getDeclName(); - - // Prevent this from triggering multiple times. - ND = 0; + // We only want to actually emit delayed diagnostics when we + // successfully parsed a decl. + Decl *D = Ctx ? Ctx.getAs<Decl>() : 0; + if (D) { + // We really do want to start with 0 here. We get one push for a + // decl spec and another for each declarator; in a decl group like: + // deprecated_typedef foo, *bar, baz(); + // only the declarator pops will be passed decls. This is correct; + // we really do need to consider delayed diagnostics from the decl spec + // for each of the different declarations. + for (unsigned I = 0, E = DelayedDiagnostics.size(); I != E; ++I) { + if (DelayedDiagnostics[I].Triggered) + continue; + + switch (DelayedDiagnostics[I].Kind) { + case DelayedDiagnostic::Deprecation: + HandleDelayedDeprecationCheck(DelayedDiagnostics[I], D); + break; + + case DelayedDiagnostic::Access: + HandleDelayedAccessCheck(DelayedDiagnostics[I], D); + break; } } } - DelayedDeprecationWarnings.set_size(SavedIndex); + DelayedDiagnostics.set_size(SavedIndex); +} + +static bool isDeclDeprecated(Decl *D) { + do { + if (D->hasAttr<DeprecatedAttr>()) + return true; + } while ((D = cast_or_null<Decl>(D->getDeclContext()))); + return false; +} + +void Sema::HandleDelayedDeprecationCheck(Sema::DelayedDiagnostic &DD, + Decl *Ctx) { + if (isDeclDeprecated(Ctx)) + return; + + DD.Triggered = true; + Diag(DD.Loc, diag::warn_deprecated) + << DD.DeprecationData.Decl->getDeclName(); } void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) { // Delay if we're currently parsing a declaration. if (ParsingDeclDepth) { - DelayedDeprecationWarnings.push_back(std::make_pair(Loc, D)); + DelayedDiagnostics.push_back(DelayedDiagnostic::makeDeprecation(Loc, D)); return; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9ec95f3d170d..9defcca7e565 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -356,9 +356,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { } } - if (CheckEquivalentExceptionSpec( - Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), - New->getType()->getAs<FunctionProtoType>(), New->getLocation())) + if (CheckEquivalentExceptionSpec(Old, New)) Invalid = true; return Invalid; @@ -433,7 +431,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, } else CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext); - if (CurDecl) + if (CurDecl && CurDecl->getIdentifier()) return &II == CurDecl->getIdentifier(); else return false; @@ -486,7 +484,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // If the base class is polymorphic or isn't empty, the new one is/isn't, too. RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl(); assert(BaseDecl && "Record type has no declaration"); - BaseDecl = BaseDecl->getDefinition(Context); + BaseDecl = BaseDecl->getDefinition(); assert(BaseDecl && "Base type is not incomplete, but has no definition"); CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl); assert(CXXBaseDecl && "Base type is not a C++ type"); @@ -641,7 +639,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, } // Attach the remaining base class specifiers to the derived class. - Class->setBases(Context, Bases, NumGoodBases); + Class->setBases(Bases, NumGoodBases); // Delete the remaining (good) base class specifiers, since their // data has been copied into the CXXRecordDecl. @@ -680,7 +678,8 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base) { CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl()); CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl()); - return DerivedRD->isDerivedFrom(BaseRD); + // FIXME: instantiate DerivedRD if necessary. We need a PoI for this. + return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD); } /// \brief Determine whether the type \p Derived is a C++ class that is @@ -712,7 +711,7 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { /// if there is an error. bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, - unsigned InaccessibleBaseID, + AccessDiagnosticsKind ADK, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name) { @@ -728,11 +727,20 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { - if (InaccessibleBaseID == 0) + if (ADK == ADK_quiet) return false; + // Check that the base class can be accessed. - return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc, - Name); + switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false, + Base, Derived, Paths.front(), + /*force*/ false, + /*unprivileged*/ false, + ADK)) { + case AR_accessible: return false; + case AR_inaccessible: return true; + case AR_dependent: return false; + case AR_delayed: return false; + } } // We know that the derived-to-base conversion is ambiguous, and @@ -763,8 +771,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, bool IgnoreAccess) { return CheckDerivedToBaseConversion(Derived, Base, - IgnoreAccess ? 0 : - diag::err_conv_to_inaccessible_base, + IgnoreAccess ? ADK_quiet : ADK_normal, diag::err_ambiguous_derived_to_base_conv, Loc, Range, DeclarationName()); } @@ -1195,10 +1202,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { - // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. - ExprTemporaries.clear(); - // Diagnose value-uses of fields to initialize themselves, e.g. // foo(foo) // where foo is not also a parameter to the constructor. @@ -1220,65 +1223,80 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); - CXXConstructorDecl *C = 0; QualType FieldType = Member->getType(); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - if (FieldType->isDependentType()) { - // Can't check init for dependent type. - } else if (FieldType->isRecordType()) { - // Member is a record (struct/union/class), so pass the initializer - // arguments down to the record's constructor. - if (!HasDependentArg) { - C = PerformInitializationByConstructor(FieldType, - MultiExprArg(*this, - (void**)Args, - NumArgs), - IdLoc, - SourceRange(IdLoc, RParenLoc), - Member->getDeclName(), - InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc), - ConstructorArgs); - - if (C) { - // Take over the constructor arguments as our own. - NumArgs = ConstructorArgs.size(); - Args = (Expr **)ConstructorArgs.take(); - } - } - } else if (NumArgs != 1 && NumArgs != 0) { - // The member type is not a record type (or an array of record - // types), so it can be only be default- or copy-initialized. - return Diag(IdLoc, diag::err_mem_initializer_mismatch) - << Member->getDeclName() << SourceRange(IdLoc, RParenLoc); - } else if (!HasDependentArg) { - Expr *NewExp; - if (NumArgs == 0) { - if (FieldType->isReferenceType()) { - Diag(IdLoc, diag::err_null_intialized_reference_member) - << Member->getDeclName(); - return Diag(Member->getLocation(), diag::note_declared_at); - } - NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc); - NumArgs = 1; - } - else - NewExp = (Expr*)Args[0]; - if (!Member->isInvalidDecl() && - PerformCopyInitialization(NewExp, FieldType, AA_Passing)) - return true; - Args[0] = NewExp; + if (FieldType->isDependentType() || HasDependentArg) { + // Can't check initialization for a member of dependent type or when + // any of the arguments are type-dependent expressions. + OwningExprResult Init + = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc)); + + // Erase any temporaries within this evaluation context; we're not + // going to track them in the AST, since we'll be rebuilding the + // ASTs during template instantiation. + ExprTemporaries.erase( + ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries, + ExprTemporaries.end()); + + return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, + LParenLoc, + Init.takeAs<Expr>(), + RParenLoc); + } - // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. - ExprTemporaries.clear(); + if (Member->isInvalidDecl()) + return true; + + // Initialize the member. + InitializedEntity MemberEntity = + InitializedEntity::InitializeMember(Member, 0); + InitializationKind Kind = + InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc); - // FIXME: Perform direct initialization of the member. + InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); + + OwningExprResult MemberInit = + InitSeq.Perform(*this, MemberEntity, Kind, + MultiExprArg(*this, (void**)Args, NumArgs), 0); + if (MemberInit.isInvalid()) + return true; + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + if (MemberInit.isInvalid()) + return true; + + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the member + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) { + // Bump the reference count of all of the arguments. + for (unsigned I = 0; I != NumArgs; ++I) + Args[I]->Retain(); + + OwningExprResult Init + = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc)); + return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, + LParenLoc, + Init.takeAs<Expr>(), + RParenLoc); + } + return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, - C, LParenLoc, (Expr **)Args, - NumArgs, RParenLoc); + LParenLoc, + MemberInit.takeAs<Expr>(), + RParenLoc); } Sema::MemInitResult @@ -1291,76 +1309,118 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, HasDependentArg |= Args[i]->isTypeDependent(); SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin(); - if (!BaseType->isDependentType()) { - if (!BaseType->isRecordType()) - return Diag(BaseLoc, diag::err_base_init_does_not_name_class) - << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); - - // C++ [class.base.init]p2: - // [...] Unless the mem-initializer-id names a nonstatic data - // member of the constructor’s class or a direct or virtual base - // of that class, the mem-initializer is ill-formed. A - // mem-initializer-list can initialize a base class using any - // name that denotes that base class type. - - // Check for direct and virtual base classes. - const CXXBaseSpecifier *DirectBaseSpec = 0; - const CXXBaseSpecifier *VirtualBaseSpec = 0; - FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, - VirtualBaseSpec); - - // C++ [base.class.init]p2: - // If a mem-initializer-id is ambiguous because it designates both - // a direct non-virtual base class and an inherited virtual base - // class, the mem-initializer is ill-formed. - if (DirectBaseSpec && VirtualBaseSpec) - return Diag(BaseLoc, diag::err_base_init_direct_and_virtual) - << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); - // C++ [base.class.init]p2: - // Unless the mem-initializer-id names a nonstatic data membeer of the - // constructor's class ot a direst or virtual base of that class, the - // mem-initializer is ill-formed. - if (!DirectBaseSpec && !VirtualBaseSpec) - return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) - << BaseType << ClassDecl->getNameAsCString() - << BaseTInfo->getTypeLoc().getSourceRange(); - } - - CXXConstructorDecl *C = 0; - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - if (!BaseType->isDependentType() && !HasDependentArg) { - DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(BaseType).getUnqualifiedType()); - - C = PerformInitializationByConstructor(BaseType, - MultiExprArg(*this, - (void**)Args, NumArgs), - BaseLoc, - SourceRange(BaseLoc, RParenLoc), - Name, - InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc), - ConstructorArgs); - if (C) { - // Take over the constructor arguments as our own. - NumArgs = ConstructorArgs.size(); - Args = (Expr **)ConstructorArgs.take(); - } + if (BaseType->isDependentType() || HasDependentArg) { + // Can't check initialization for a base of dependent type or when + // any of the arguments are type-dependent expressions. + OwningExprResult BaseInit + = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc)); + + // Erase any temporaries within this evaluation context; we're not + // going to track them in the AST, since we'll be rebuilding the + // ASTs during template instantiation. + ExprTemporaries.erase( + ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries, + ExprTemporaries.end()); + + return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + LParenLoc, + BaseInit.takeAs<Expr>(), + RParenLoc); } + + if (!BaseType->isRecordType()) + return Diag(BaseLoc, diag::err_base_init_does_not_name_class) + << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); - // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. - ExprTemporaries.clear(); + // C++ [class.base.init]p2: + // [...] Unless the mem-initializer-id names a nonstatic data + // member of the constructor’s class or a direct or virtual base + // of that class, the mem-initializer is ill-formed. A + // mem-initializer-list can initialize a base class using any + // name that denotes that base class type. + + // Check for direct and virtual base classes. + const CXXBaseSpecifier *DirectBaseSpec = 0; + const CXXBaseSpecifier *VirtualBaseSpec = 0; + FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, + VirtualBaseSpec); + + // C++ [base.class.init]p2: + // If a mem-initializer-id is ambiguous because it designates both + // a direct non-virtual base class and an inherited virtual base + // class, the mem-initializer is ill-formed. + if (DirectBaseSpec && VirtualBaseSpec) + return Diag(BaseLoc, diag::err_base_init_direct_and_virtual) + << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); + // C++ [base.class.init]p2: + // Unless the mem-initializer-id names a nonstatic data membeer of the + // constructor's class ot a direst or virtual base of that class, the + // mem-initializer is ill-formed. + if (!DirectBaseSpec && !VirtualBaseSpec) + return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) + << BaseType << ClassDecl->getNameAsCString() + << BaseTInfo->getTypeLoc().getSourceRange(); + + CXXBaseSpecifier *BaseSpec + = const_cast<CXXBaseSpecifier *>(DirectBaseSpec); + if (!BaseSpec) + BaseSpec = const_cast<CXXBaseSpecifier *>(VirtualBaseSpec); + + // Initialize the base. + InitializedEntity BaseEntity = + InitializedEntity::InitializeBase(Context, BaseSpec); + InitializationKind Kind = + InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc); + + InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs); + + OwningExprResult BaseInit = + InitSeq.Perform(*this, BaseEntity, Kind, + MultiExprArg(*this, (void**)Args, NumArgs), 0); + if (BaseInit.isInvalid()) + return true; - return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, C, - LParenLoc, (Expr **)Args, - NumArgs, RParenLoc); + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) + return true; + + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the base + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) { + // Bump the reference count of all of the arguments. + for (unsigned I = 0; I != NumArgs; ++I) + Args[I]->Retain(); + + OwningExprResult Init + = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc)); + return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + LParenLoc, + Init.takeAs<Expr>(), + RParenLoc); + } + + return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + LParenLoc, + BaseInit.takeAs<Expr>(), + RParenLoc); } bool Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers, - bool IsImplicitConstructor) { + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers, + bool IsImplicitConstructor, + bool AnyErrors) { // 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()); @@ -1403,6 +1463,8 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, AllToInit.push_back(Member); } } else { + llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit; + // Push virtual bases before others. for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), @@ -1412,44 +1474,34 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); - } - else { - CXXRecordDecl *VBaseDecl = - cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null"); - CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context); - if (!Ctor) { - Diag(Constructor->getLocation(), diag::err_missing_default_ctor) - << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) - << 0 << VBase->getType(); - Diag(VBaseDecl->getLocation(), diag::note_previous_decl) - << Context.getTagDeclType(VBaseDecl); + } 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; } - ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); - if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), - Constructor->getLocation(), CtorArgs)) + // Don't attach synthesized base initializers in a dependent + // context; they'll be checked again at template instantiation + // time. + if (CurContext->isDependentContext()) continue; - MarkDeclarationReferenced(Constructor->getLocation(), Ctor); - - // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if - // necessary. - // FIXME: Is there any better source-location information we can give? - ExprTemporaries.clear(); - CXXBaseOrMemberInitializer *Member = + CXXBaseOrMemberInitializer *CXXBaseInit = new (Context) CXXBaseOrMemberInitializer(Context, Context.getTrivialTypeSourceInfo(VBase->getType(), SourceLocation()), - Ctor, SourceLocation(), - CtorArgs.takeAs<Expr>(), - CtorArgs.size(), + BaseInit.takeAs<Expr>(), SourceLocation()); - AllToInit.push_back(Member); + AllToInit.push_back(CXXBaseInit); } } @@ -1466,43 +1518,34 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); } - else { - CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); - CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context); - if (!Ctor) { - Diag(Constructor->getLocation(), diag::err_missing_default_ctor) - << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) - << 0 << Base->getType(); - Diag(BaseDecl->getLocation(), diag::note_previous_decl) - << Context.getTagDeclType(BaseDecl); + 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; } - - ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); - if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), - Constructor->getLocation(), CtorArgs)) + + // Don't attach synthesized base initializers in a dependent + // context; they'll be regenerated at template instantiation + // time. + if (CurContext->isDependentContext()) continue; - MarkDeclarationReferenced(Constructor->getLocation(), Ctor); - - // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if - // necessary. - // FIXME: Is there any better source-location information we can give? - ExprTemporaries.clear(); - CXXBaseOrMemberInitializer *Member = + CXXBaseOrMemberInitializer *CXXBaseInit = new (Context) CXXBaseOrMemberInitializer(Context, Context.getTrivialTypeSourceInfo(Base->getType(), SourceLocation()), - Ctor, SourceLocation(), - CtorArgs.takeAs<Expr>(), - CtorArgs.size(), + BaseInit.takeAs<Expr>(), SourceLocation()); - AllToInit.push_back(Member); + AllToInit.push_back(CXXBaseInit); } } } @@ -1535,66 +1578,49 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; } - if ((*Field)->getType()->isDependentType()) + if ((*Field)->getType()->isDependentType() || AnyErrors) continue; QualType FT = Context.getBaseElementType((*Field)->getType()); - if (const RecordType* RT = FT->getAs<RecordType>()) { - CXXConstructorDecl *Ctor = - cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context); - if (!Ctor) { - Diag(Constructor->getLocation(), diag::err_missing_default_ctor) - << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) - << 1 << (*Field)->getDeclName(); - Diag(Field->getLocation(), diag::note_field_decl); - Diag(RT->getDecl()->getLocation(), diag::note_previous_decl) - << Context.getTagDeclType(RT->getDecl()); + if (FT->getAs<RecordType>()) { + InitializedEntity InitEntity + = InitializedEntity::InitializeMember(*Field); + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + OwningExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind, + MultiExprArg(*this, 0, 0)); + MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + if (MemberInit.isInvalid()) { HadError = true; continue; } - - if (FT.isConstQualified() && Ctor->isTrivial()) { - Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) - << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) - << 1 << (*Field)->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); - HadError = true; - } - - // Don't create initializers for trivial constructors, since they don't - // actually need to be run. - if (Ctor->isTrivial()) - continue; - - ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); - if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), - Constructor->getLocation(), CtorArgs)) + + // Don't attach synthesized member initializers in a dependent + // context; they'll be regenerated a template instantiation + // time. + if (CurContext->isDependentContext()) continue; - // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. - ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = new (Context) CXXBaseOrMemberInitializer(Context, *Field, SourceLocation(), - Ctor, SourceLocation(), - CtorArgs.takeAs<Expr>(), - CtorArgs.size(), + MemberInit.takeAs<Expr>(), SourceLocation()); AllToInit.push_back(Member); - MarkDeclarationReferenced(Constructor->getLocation(), Ctor); } else if (FT->isReferenceType()) { - Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) + Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); HadError = true; } else if (FT.isConstQualified()) { - Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) + Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); @@ -1659,7 +1685,8 @@ static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member, /// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, - MemInitTy **MemInits, unsigned NumMemInits) { + MemInitTy **MemInits, unsigned NumMemInits, + bool AnyErrors) { if (!ConstructorDecl) return; @@ -1709,7 +1736,7 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, SetBaseOrMemberInitializers(Constructor, reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits), - NumMemInits, false); + NumMemInits, false, AnyErrors); if (Constructor->isDependentContext()) return; @@ -1860,7 +1887,7 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>())) - SetBaseOrMemberInitializers(Constructor, 0, 0, false); + SetBaseOrMemberInitializers(Constructor, 0, 0, false, false); } namespace { @@ -1978,13 +2005,15 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, if (!RT) return false; - const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); - if (!RD) - return false; + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); if (CurrentRD && CurrentRD != RD) return false; + // FIXME: is this reasonable? It matches current behavior, but.... + if (!RD->getDefinition()) + return false; + if (!RD->isAbstract()) return false; @@ -2086,6 +2115,11 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (Record->isInvalidDecl()) return; + // Set access bits correctly on the directly-declared conversions. + UnresolvedSetImpl *Convs = Record->getConversionFunctions(); + 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. @@ -2227,7 +2261,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, VarDecl::None, 0); - CopyConstructor->setParams(Context, &FromParam, 1); + CopyConstructor->setParams(&FromParam, 1); ClassDecl->addDecl(CopyConstructor); } @@ -2311,7 +2345,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, VarDecl::None, 0); - CopyAssignment->setParams(Context, &FromParam, 1); + CopyAssignment->setParams(&FromParam, 1); // Don't call addedAssignmentOperator. There is no way to distinguish an // implicit from an explicit assignment operator. @@ -2793,13 +2827,16 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, SourceLocation IdentLoc, IdentifierInfo *II, - SourceLocation LBrace) { + SourceLocation LBrace, + AttributeList *AttrList) { NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IdentLoc, II); Namespc->setLBracLoc(LBrace); Scope *DeclRegionScope = NamespcScope->getParent(); + ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); + if (II) { // C++ [namespace.def]p2: // The identifier in an original-namespace-definition shall not have been @@ -3654,7 +3691,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, (NestedNameSpecifier *)SS.getScopeRep(), IdentLoc, R.getFoundDecl()); - CurContext->addDecl(AliasDecl); + PushOnScopeChains(AliasDecl, S); return DeclPtrTy::make(AliasDecl); } @@ -3668,13 +3705,16 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, = cast<CXXRecordDecl>(Constructor->getDeclContext()); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); - if (SetBaseOrMemberInitializers(Constructor, 0, 0, true)) { + DeclContext *PreviousContext = CurContext; + CurContext = Constructor; + if (SetBaseOrMemberInitializers(Constructor, 0, 0, true, false)) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); } else { Constructor->setUsed(); } + CurContext = PreviousContext; } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, @@ -3683,6 +3723,10 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, "DefineImplicitDestructor - call it for implicit default dtor"); CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); + + DeclContext *PreviousContext = CurContext; + CurContext = Destructor; + // C++ [class.dtor] p5 // Before the implicitly-declared default destructor for a class is // implicitly defined, all the implicitly-declared default destructors @@ -3729,8 +3773,11 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, << CXXDestructor << Context.getTagDeclType(ClassDecl); Destructor->setInvalidDecl(); + CurContext = PreviousContext; + return; } + CurContext = PreviousContext; Destructor->setUsed(); } @@ -3745,6 +3792,9 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MethodDecl->getDeclContext()); + DeclContext *PreviousContext = CurContext; + CurContext = MethodDecl; + // C++[class.copy] p12 // Before the implicitly-declared copy assignment operator for a class is // implicitly defined, all implicitly-declared copy assignment operators @@ -3788,6 +3838,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, } if (!err) MethodDecl->setUsed(); + + CurContext = PreviousContext; } CXXMethodDecl * @@ -3808,7 +3860,7 @@ Sema::getAssignOperatorMethod(SourceLocation CurrentLocation, RHSType, CurrentLocation)); Expr *Args[2] = { &*LHS, &*RHS }; - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(CurrentLocation); AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2, CandidateSet); OverloadCandidateSet::iterator Best; @@ -3830,6 +3882,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CopyConstructor->getDeclContext()); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); + + DeclContext *PreviousContext = CurContext; + CurContext = CopyConstructor; + // C++ [class.copy] p209 // Before the implicitly-declared copy constructor for a class is // implicitly defined, all the implicitly-declared copy constructors @@ -3858,13 +3914,16 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, } } CopyConstructor->setUsed(); + + CurContext = PreviousContext; } Sema::OwningExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, - bool RequiresZeroInit) { + bool RequiresZeroInit, + bool BaseInitialization) { bool Elidable = false; // C++ [class.copy]p15: @@ -3897,7 +3956,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, } return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, - Elidable, move(ExprArgs), RequiresZeroInit); + Elidable, move(ExprArgs), RequiresZeroInit, + BaseInitialization); } /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -3906,32 +3966,17 @@ Sema::OwningExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs, - bool RequiresZeroInit) { + bool RequiresZeroInit, + bool BaseInitialization) { unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); MarkDeclarationReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, - RequiresZeroInit)); -} - -Sema::OwningExprResult -Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor, - QualType Ty, - SourceLocation TyBeginLoc, - MultiExprArg Args, - SourceLocation RParenLoc) { - unsigned NumExprs = Args.size(); - Expr **Exprs = (Expr **)Args.release(); - - MarkDeclarationReferenced(TyBeginLoc, Constructor); - return Owned(new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty, - TyBeginLoc, Exprs, - NumExprs, RParenLoc)); + RequiresZeroInit, BaseInitialization)); } - bool Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, MultiExprArg Exprs) { @@ -3944,18 +3989,18 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD, Expr *Temp = TempResult.takeAs<Expr>(); MarkDeclarationReferenced(VD->getLocation(), Constructor); Temp = MaybeCreateCXXExprWithTemporaries(Temp); - VD->setInit(Context, Temp); + VD->setInit(Temp); return false; } -void Sema::FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>( - DeclInitType->getAs<RecordType>()->getDecl()); - if (!ClassDecl->hasTrivialDestructor()) - if (CXXDestructorDecl *Destructor = - const_cast<CXXDestructorDecl*>(ClassDecl->getDestructor(Context))) - MarkDeclarationReferenced(VD->getLocation(), Destructor); +void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl()); + if (!ClassDecl->hasTrivialDestructor()) { + CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context); + MarkDeclarationReferenced(VD->getLocation(), Destructor); + CheckDestructorAccess(VD->getLocation(), Record); + } } /// AddCXXDirectInitializerToDecl - This action is called immediately after @@ -3991,24 +4036,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, // exactly form was it (like the CodeGen) can handle both cases without // special case code. - // If either the declaration has a dependent type or if any of the expressions - // is type-dependent, we represent the initialization via a ParenListExpr for - // later use during template instantiation. - if (VDecl->getType()->isDependentType() || - Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) { - // Let clients know that initialization was done with a direct initializer. - VDecl->setCXXDirectInitializer(true); - - // Store the initialization expressions as a ParenListExpr. - unsigned NumExprs = Exprs.size(); - VDecl->setInit(Context, - new (Context) ParenListExpr(Context, LParenLoc, - (Expr **)Exprs.release(), - NumExprs, RParenLoc)); - return; - } - - // C++ 8.5p11: // The form of initialization (using parentheses or '=') is generally // insignificant, but does matter when the entity being initialized has a @@ -4017,7 +4044,8 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, if (const ArrayType *Array = Context.getAsArrayType(DeclInitType)) DeclInitType = Context.getBaseElementType(Array); - if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(), + if (!VDecl->getType()->isDependentType() && + RequireCompleteType(VDecl->getLocation(), VDecl->getType(), diag::err_typecheck_decl_incomplete_type)) { VDecl->setInvalidDecl(); return; @@ -4029,14 +4057,30 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, AbstractVariableType)) VDecl->setInvalidDecl(); - const VarDecl *Def = 0; - if (VDecl->getDefinition(Def)) { + const VarDecl *Def; + if ((Def = VDecl->getDefinition()) && Def != VDecl) { Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); Diag(Def->getLocation(), diag::note_previous_definition); VDecl->setInvalidDecl(); return; } + + // If either the declaration has a dependent type or if any of the + // expressions is type-dependent, we represent the initialization + // via a ParenListExpr for later use during template instantiation. + if (VDecl->getType()->isDependentType() || + Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) { + // Let clients know that initialization was done with a direct initializer. + VDecl->setCXXDirectInitializer(true); + + // Store the initialization expressions as a ParenListExpr. + unsigned NumExprs = Exprs.size(); + VDecl->setInit(new (Context) ParenListExpr(Context, LParenLoc, + (Expr **)Exprs.release(), + NumExprs, RParenLoc)); + return; + } // Capture the variable that is being initialized and the style of // initialization. @@ -4056,11 +4100,11 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, } Result = MaybeCreateCXXExprWithTemporaries(move(Result)); - VDecl->setInit(Context, Result.takeAs<Expr>()); + VDecl->setInit(Result.takeAs<Expr>()); VDecl->setCXXDirectInitializer(true); - if (VDecl->getType()->getAs<RecordType>()) - FinalizeVarWithDestructor(VDecl, DeclInitType); + if (const RecordType *Record = VDecl->getType()->getAs<RecordType>()) + FinalizeVarWithDestructor(VDecl, Record); } /// \brief Add the applicable constructor candidates for an initialization @@ -4112,10 +4156,12 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, Constructor->isDefaultConstructor())) { if (ConstructorTmpl) SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, + ConstructorTmpl->getAccess(), /*ExplicitArgs*/ 0, Args, NumArgs, CandidateSet); else - SemaRef.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + SemaRef.AddOverloadCandidate(Constructor, Constructor->getAccess(), + Args, NumArgs, CandidateSet); } } } @@ -4145,7 +4191,7 @@ Sema::TryInitializationByConstructor(QualType ClassType, SourceLocation Loc, InitializationKind Kind) { // Build the overload candidate set - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(Loc); AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind, CandidateSet); @@ -4167,92 +4213,6 @@ Sema::TryInitializationByConstructor(QualType ClassType, return 0; } -/// \brief Perform initialization by constructor (C++ [dcl.init]p14), which -/// may occur as part of direct-initialization or copy-initialization. -/// -/// \param ClassType the type of the object being initialized, which must have -/// class type. -/// -/// \param ArgsPtr the arguments provided to initialize the object -/// -/// \param Loc the source location where the initialization occurs -/// -/// \param Range the source range that covers the entire initialization -/// -/// \param InitEntity the name of the entity being initialized, if known -/// -/// \param Kind the type of initialization being performed -/// -/// \param ConvertedArgs a vector that will be filled in with the -/// appropriately-converted arguments to the constructor (if initialization -/// succeeded). -/// -/// \returns the constructor used to initialize the object, if successful. -/// Otherwise, emits a diagnostic and returns NULL. -CXXConstructorDecl * -Sema::PerformInitializationByConstructor(QualType ClassType, - MultiExprArg ArgsPtr, - SourceLocation Loc, SourceRange Range, - DeclarationName InitEntity, - InitializationKind Kind, - ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) { - - // Build the overload candidate set - Expr **Args = (Expr **)ArgsPtr.get(); - unsigned NumArgs = ArgsPtr.size(); - OverloadCandidateSet CandidateSet; - AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind, - CandidateSet); - - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, Loc, Best)) { - case OR_Success: - // We found a constructor. Break out so that we can convert the arguments - // appropriately. - break; - - case OR_No_Viable_Function: - if (InitEntity) - Diag(Loc, diag::err_ovl_no_viable_function_in_init) - << InitEntity << Range; - else - Diag(Loc, diag::err_ovl_no_viable_function_in_init) - << ClassType << Range; - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); - return 0; - - case OR_Ambiguous: - if (InitEntity) - Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range; - else - Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range; - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs); - return 0; - - case OR_Deleted: - if (InitEntity) - Diag(Loc, diag::err_ovl_deleted_init) - << Best->Function->isDeleted() - << InitEntity << Range; - else { - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(ClassType->getAs<RecordType>()->getDecl()); - Diag(Loc, diag::err_ovl_deleted_init) - << Best->Function->isDeleted() - << RD->getDeclName() << Range; - } - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); - return 0; - } - - // Convert the arguments, fill in default arguments, etc. - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function); - if (CompleteConstructorCall(Constructor, move(ArgsPtr), Loc, ConvertedArgs)) - return 0; - - return Constructor; -} - /// \brief Given a constructor and the set of arguments provided for the /// constructor, convert the arguments and add any required default arguments /// to form a proper call to this constructor. @@ -4453,7 +4413,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; ICS->Standard.Third = ICK_Identity; ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS->Standard.ToTypePtr = T1.getAsOpaquePtr(); + ICS->Standard.setToType(0, T2); + ICS->Standard.setToType(1, T1); + ICS->Standard.setToType(2, T1); ICS->Standard.ReferenceBinding = true; ICS->Standard.DirectBinding = true; ICS->Standard.RRefBinding = false; @@ -4486,7 +4448,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, CXXRecordDecl *T2RecordDecl = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(DeclLoc); const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), @@ -4509,10 +4471,11 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (Conv->getConversionType()->isLValueReferenceType() && (AllowExplicit || !Conv->isExplicit())) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, ActingDC, + AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), ActingDC, Init, DeclType, CandidateSet); else - AddConversionCandidate(Conv, ActingDC, Init, DeclType, CandidateSet); + AddConversionCandidate(Conv, I.getAccess(), ActingDC, Init, + DeclType, CandidateSet); } } @@ -4606,6 +4569,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) { if (!ICS) Diag(DeclLoc, diag::err_not_reference_to_const_init) + << T1.isVolatileQualified() << T1 << int(InitLvalue != Expr::LV_Valid) << T2 << Init->getSourceRange(); return true; @@ -4642,7 +4606,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; ICS->Standard.Third = ICK_Identity; ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS->Standard.ToTypePtr = T1.getAsOpaquePtr(); + ICS->Standard.setToType(0, T2); + ICS->Standard.setToType(1, T1); + ICS->Standard.setToType(2, T1); ICS->Standard.ReferenceBinding = true; ICS->Standard.DirectBinding = false; ICS->Standard.RRefBinding = isRValRef; @@ -5611,7 +5577,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType(); QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType(); - if (Context.hasSameType(NewTy, OldTy)) + if (Context.hasSameType(NewTy, OldTy) || + NewTy->isDependentType() || OldTy->isDependentType()) return false; // Check if the return types are covariant @@ -5665,8 +5632,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, } // Check if we the conversion from derived to base is valid. - if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, - diag::err_covariant_return_inaccessible_base, + if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance, diag::err_covariant_return_ambiguous_derived_to_base_conv, // FIXME: Should this point to the return type? New->getLocation(), SourceRange(), New->getDeclName())) { diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 1b07d19882e0..1e9b56a90ed6 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -446,18 +446,19 @@ Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, // Category ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); assert (CatDecl && "MatchOneProtocolPropertiesInClass"); - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Pr = (*P); - ObjCCategoryDecl::prop_iterator CP, CE; - // Is this property already in category's list of properties? - for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP) - if ((*CP)->getIdentifier() == Pr->getIdentifier()) - break; - if (CP != CE) - // Property protocol already exist in class. Diagnose any mismatch. - DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); - } + if (!CatDecl->IsClassExtension()) + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCCategoryDecl::prop_iterator CP, CE; + // Is this property already in category's list of properties? + for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP) + if ((*CP)->getIdentifier() == Pr->getIdentifier()) + break; + if (CP != CE) + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); + } return; } for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), @@ -596,44 +597,59 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { - ObjCCategoryDecl *CDecl = - ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, - CategoryLoc, CategoryName); - // FIXME: PushOnScopeChains? - CurContext->addDecl(CDecl); - + ObjCCategoryDecl *CDecl = 0; ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); - /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) { - CDecl->setInvalidDecl(); - Diag(ClassLoc, diag::err_undef_interface) << ClassName; - return DeclPtrTy::make(CDecl); - } + if (!CategoryName) { + // Class extensions require a special treatment. Use an existing one. + for (CDecl = IDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) + if (CDecl->IsClassExtension()) + break; + } + if (!CDecl) { + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, + CategoryLoc, CategoryName); + // FIXME: PushOnScopeChains? + CurContext->addDecl(CDecl); + + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->isForwardDecl()) { + CDecl->setInvalidDecl(); + Diag(ClassLoc, diag::err_undef_interface) << ClassName; + return DeclPtrTy::make(CDecl); + } - CDecl->setClassInterface(IDecl); + CDecl->setClassInterface(IDecl); + // Insert first use of class extension to the list of class's categories. + if (!CategoryName) + CDecl->insertNextClassCategory(); + } // If the interface is deprecated, warn about it. (void)DiagnoseUseOfDecl(IDecl, ClassLoc); - /// Check for duplicate interface declaration for this category - ObjCCategoryDecl *CDeclChain; - for (CDeclChain = IDecl->getCategoryList(); CDeclChain; - CDeclChain = CDeclChain->getNextClassCategory()) { - if (CategoryName && CDeclChain->getIdentifier() == CategoryName) { - Diag(CategoryLoc, diag::warn_dup_category_def) - << ClassName << CategoryName; - Diag(CDeclChain->getLocation(), diag::note_previous_definition); - break; + if (CategoryName) { + /// Check for duplicate interface declaration for this category + ObjCCategoryDecl *CDeclChain; + for (CDeclChain = IDecl->getCategoryList(); CDeclChain; + CDeclChain = CDeclChain->getNextClassCategory()) { + if (CDeclChain->getIdentifier() == CategoryName) { + // Class extensions can be declared multiple times. + Diag(CategoryLoc, diag::warn_dup_category_def) + << ClassName << CategoryName; + Diag(CDeclChain->getLocation(), diag::note_previous_definition); + break; + } } + if (!CDeclChain) + CDecl->insertNextClassCategory(); } - if (!CDeclChain) - CDecl->insertNextClassCategory(); if (NumProtoRefs) { CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, ProtoLocs, Context); // Protocols in the class extension belong to the class. - if (!CDecl->getIdentifier()) + if (CDecl->IsClassExtension()) IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, ProtoLocs, Context); @@ -1102,11 +1118,12 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, CollectImmediateProperties((*PI), PropMap); } if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { - for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), - E = CATDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - PropMap[Prop->getIdentifier()] = Prop; - } + if (!CATDecl->IsClassExtension()) + for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), + E = CATDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } // scan through class's protocols. for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), E = CATDecl->protocol_end(); PI != E; ++PI) @@ -1127,6 +1144,46 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, } } +/// LookupPropertyDecl - Looks up a property in the current class and all +/// its protocols. +ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, + IdentifierInfo *II) { + if (const ObjCInterfaceDecl *IDecl = + dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), + E = IDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + if (Prop->getIdentifier() == II) + return Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), + E = IDecl->protocol_end(); PI != E; ++PI) { + ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); + if (Prop) + return Prop; + } + } + else if (const ObjCProtocolDecl *PDecl = + dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + if (Prop->getIdentifier() == II) + return Prop; + } + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) { + ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); + if (Prop) + return Prop; + } + } + return 0; +} + + void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet<Selector>& InsMap) { @@ -1149,7 +1206,14 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || PropImplMap.count(Prop)) continue; - + if (LangOpts.ObjCNonFragileABI2) { + ActOnPropertyImplDecl(IMPDecl->getLocation(), + SourceLocation(), + true, DeclPtrTy::make(IMPDecl), + Prop->getIdentifier(), + Prop->getIdentifier()); + continue; + } if (!InsMap.count(Prop->getGetterName())) { Diag(Prop->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? @@ -1214,7 +1278,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, // Check class extensions (unnamed categories) for (ObjCCategoryDecl *Categories = I->getCategoryList(); Categories; Categories = Categories->getNextClassCategory()) { - if (!Categories->getIdentifier()) { + if (Categories->IsClassExtension()) { ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl); break; } @@ -1222,7 +1286,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) { // For extended class, unimplemented methods in its protocols will // be reported in the primary class. - if (C->getIdentifier()) { + if (!C->IsClassExtension()) { for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, @@ -1443,7 +1507,8 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". - Entry.Next = new ObjCMethodList(Method, Entry.Next); + ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>(); + Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next); } // FIXME: Finish implementing -Wno-strict-selector-match. @@ -1506,7 +1571,8 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) { if (!match) { // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". - struct ObjCMethodList *OMI = new ObjCMethodList(Method, FirstMethod.Next); + ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>(); + ObjCMethodList *OMI = new (Mem) ObjCMethodList(Method, FirstMethod.Next); FirstMethod.Next = OMI; } } @@ -1777,17 +1843,18 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, // Compare protocol properties with those in category CompareProperties(C, DeclPtrTy::make(C)); - if (C->getIdentifier() == 0) + if (C->IsClassExtension()) DiagnoseClassExtensionDupMethods(C, C->getClassInterface()); } if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) { - // ProcessPropertyDecl is responsible for diagnosing conflicts with any - // user-defined setter/getter. It also synthesizes setter/getter methods - // and adds them to the DeclContext and global method pools. - for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), - E = CDecl->prop_end(); - I != E; ++I) - ProcessPropertyDecl(*I, CDecl); + if (CDecl->getIdentifier()) + // ProcessPropertyDecl is responsible for diagnosing conflicts with any + // user-defined setter/getter. It also synthesizes setter/getter methods + // and adds them to the DeclContext and global method pools. + for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), + E = CDecl->prop_end(); + I != E; ++I) + ProcessPropertyDecl(*I, CDecl); CDecl->setAtEndRange(AtEnd); } if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { @@ -2088,7 +2155,22 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, // May modify Attributes. CheckObjCPropertyAttributes(T, AtLoc, Attributes); if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) - if (!CDecl->getIdentifier()) { + if (CDecl->IsClassExtension()) { + // Diagnose if this property is already in continuation class. + DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); + assert(DC && "ClassDecl is not a DeclContext"); + DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier()); + if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) { + Diag(AtLoc, diag::err_duplicate_property); + Diag((*Found.first)->getLocation(), diag::note_property_declare); + return DeclPtrTy(); + } + ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, + FD.D.getIdentifierLoc(), + FD.D.getIdentifier(), + AtLoc, T); + DC->addDecl(PDecl); + // This is a continuation class. property requires special // handling. if ((CCPrimary = CDecl->getClassInterface())) { @@ -2152,6 +2234,7 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, ProcessPropertyDecl(PIDecl, CCPrimary); return DeclPtrTy(); } + // No matching property found in the primary class. Just fall thru // and add property to continuation class's primary class. ClassDecl = CCPrimary; @@ -2246,6 +2329,28 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, return DeclPtrTy::make(PDecl); } +ObjCIvarDecl* +Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, + IdentifierInfo *NameII) { + ObjCIvarDecl *Ivar = 0; + ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII); + if (Prop && !Prop->isInvalidDecl()) { + DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl); + QualType PropType = Context.getCanonicalType(Prop->getType()); + assert(EnclosingContext && + "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar"); + Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, + Prop->getLocation(), + NameII, PropType, /*Dinfo=*/0, + ObjCIvarDecl::Public, + (Expr *)0); + Ivar->setLexicalDeclContext(IDecl); + IDecl->addDecl(Ivar); + Prop->setPropertyIvarDecl(Ivar); + } + return Ivar; +} + /// ActOnPropertyImplDecl - This routine performs semantic checks and /// builds the AST node for a property implementation declaration; declared /// as @synthesize or @dynamic. @@ -2283,7 +2388,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, } if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { - if (CD->getIdentifier()) { + if (!CD->IsClassExtension()) { Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); Diag(property->getLocation(), diag::note_property_declare); return DeclPtrTy(); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 7e2a98d0bf1f..9be411b552ad 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -12,10 +12,11 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "clang/Basic/Diagnostic.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { @@ -92,6 +93,52 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { return FnT->hasExceptionSpec(); } +bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { + bool MissingEmptyExceptionSpecification = false; + if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, + diag::note_previous_declaration, + Old->getType()->getAs<FunctionProtoType>(), + Old->getLocation(), + New->getType()->getAs<FunctionProtoType>(), + New->getLocation(), + &MissingEmptyExceptionSpecification)) + return false; + + // The failure was something other than an empty exception + // specification; return an error. + if (!MissingEmptyExceptionSpecification) + return true; + + // The new function declaration is only missing an empty exception + // specification "throw()". If the throw() specification came from a + // function in a system header that has C linkage, just add an empty + // exception specification to the "new" declaration. This is an + // egregious workaround for glibc, which adds throw() specifications + // 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()) && + Old->isExternC()) { + const FunctionProtoType *NewProto + = cast<FunctionProtoType>(New->getType()); + QualType NewType = Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + NewProto->isVariadic(), + NewProto->getTypeQuals(), + true, false, 0, 0, + NewProto->getNoReturnAttr(), + NewProto->getCallConv()); + New->setType(NewType); + return false; + } + + Diag(New->getLocation(), diag::err_mismatched_exception_spec); + Diag(Old->getLocation(), diag::note_previous_declaration); + return true; +} + /// CheckEquivalentExceptionSpec - Check if the two types have equivalent /// exception specifications. Exception specifications are equivalent if /// they allow exactly the same set of exception types. It does not matter how @@ -111,12 +158,26 @@ bool Sema::CheckEquivalentExceptionSpec( bool Sema::CheckEquivalentExceptionSpec( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc) { + const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingEmptyExceptionSpecification) { + if (MissingEmptyExceptionSpecification) + *MissingEmptyExceptionSpecification = false; + bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec(); bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec(); if (OldAny && NewAny) return false; if (OldAny || NewAny) { + if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() && + !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 && + !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; + return true; + } + Diag(NewLoc, DiagID); if (NoteID.getDiagID() != 0) Diag(OldLoc, NoteID); @@ -232,8 +293,22 @@ bool Sema::CheckExceptionSpecSubset( if (Paths.isAmbiguous(CanonicalSuperT)) continue; - if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true)) - continue; + // Do this check from a context without privileges. + switch (CheckBaseClassAccess(SourceLocation(), false, + CanonicalSuperT, CanonicalSubT, + Paths.front(), + /*ForceCheck*/ true, + /*ForceUnprivileged*/ true, + ADK_quiet)) { + case AR_accessible: break; + case AR_inaccessible: continue; + case AR_dependent: + llvm_unreachable("access check dependent for unprivileged context"); + break; + case AR_delayed: + llvm_unreachable("access check delayed in non-declaration"); + break; + } Contained = true; break; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 50976f7b704b..633884f673ba 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -14,7 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/AnalysisContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -200,6 +200,28 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { } } +void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { + DefaultFunctionArrayConversion(E); + + QualType Ty = E->getType(); + assert(!Ty.isNull() && "DefaultFunctionArrayLvalueConversion - missing type"); + if (!Ty->isDependentType() && Ty.hasQualifiers() && + (!getLangOptions().CPlusPlus || !Ty->isRecordType()) && + E->isLvalue(Context) == Expr::LV_Valid) { + // C++ [conv.lval]p1: + // [...] If T is a non-class type, the type of the rvalue is the + // cv-unqualified version of T. Otherwise, the type of the + // rvalue is T + // + // C99 6.3.2.1p2: + // If the lvalue has qualified type, the value has the unqualified + // version of the type of the lvalue; otherwise, the value has the + // type of the lvalue. + ImpCastExprToType(E, Ty.getUnqualifiedType(), CastExpr::CK_NoOp); + } +} + + /// UsualUnaryConversions - Performs various conversions that are common to most /// operators (C99 6.3). The conversions of array and function types are /// sometimes surpressed. For example, the array->pointer conversion doesn't @@ -233,7 +255,7 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) { return Expr; } - DefaultFunctionArrayConversion(Expr); + DefaultFunctionArrayLvalueConversion(Expr); return Expr; } @@ -678,7 +700,13 @@ static void DecomposeTemplateName(LookupResult &R, const UnqualifiedId &Id) { R.resolveKind(); } +/// Determines whether the given record is "fully-formed" at the given +/// location, i.e. whether a qualified lookup into it is assured of +/// getting consistent results already. static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) { + if (!Record->hasDefinition()) + return false; + for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); @@ -686,7 +714,7 @@ static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) { if (!BaseRT) return false; CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); - if (!BaseRecord->isDefinition() || + if (!BaseRecord->hasDefinition() || !IsFullyFormedScope(SemaRef, BaseRecord)) return false; } @@ -719,7 +747,7 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef, if (Bases.count(Record->getCanonicalDecl())) return false; - RecordDecl *RD = Record->getDefinition(SemaRef.Context); + RecordDecl *RD = Record->getDefinition(); if (!RD) return false; Record = cast<CXXRecordDecl>(RD); @@ -1243,9 +1271,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, else LookForIvars = (Lookup.isSingleResult() && Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()); - + ObjCInterfaceDecl *IFace = 0; if (LookForIvars) { - ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); + IFace = getCurMethodDecl()->getClassInterface(); ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { // Diagnose using an ivar in a class method. @@ -1314,6 +1342,11 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, } } } + if (LangOpts.ObjCNonFragileABI2 && LookForIvars && Lookup.empty()) { + ObjCIvarDecl *Ivar = SynthesizeNewPropertyIvar(IFace, II); + if (Ivar) + return LookupInObjCMethod(Lookup, S, II, AllowBuiltinCreation); + } // Sentinel value saying that we didn't do anything special. return Owned((Expr*) 0); } @@ -1487,7 +1520,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, bool NeedsADL) { // If this is a single, fully-resolved result and we don't need ADL, // just build an ordinary singleton decl ref. - if (!NeedsADL && R.isSingleResult()) + if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>()) return BuildDeclarationNameExpr(SS, R.getNameLoc(), R.getFoundDecl()); // We only need to check the declaration if there's exactly one @@ -1497,16 +1530,20 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl())) return ExprError(); + // Otherwise, just build an unresolved lookup expression. Suppress + // any lookup-related diagnostics; we'll hash these out later, when + // we've picked a target. + R.suppressDiagnostics(); + bool Dependent = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), 0); UnresolvedLookupExpr *ULE - = UnresolvedLookupExpr::Create(Context, Dependent, + = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(), (NestedNameSpecifier*) SS.getScopeRep(), SS.getRange(), R.getLookupName(), R.getNameLoc(), NeedsADL, R.isOverloadedResult()); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - ULE->addDecl(*I); + ULE->addDecls(R.begin(), R.end()); return Owned(ULE); } @@ -1616,8 +1653,7 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, if (cast<DeclContext>(currentDecl)->isDependentContext()) { ResTy = Context.DependentTy; } else { - unsigned Length = - PredefinedExpr::ComputeName(Context, IT, currentDecl).length(); + unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length(); llvm::APInt LengthI(32, Length + 1); ResTy = Context.CharTy.withConst(); @@ -1642,6 +1678,8 @@ Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) { Ty = Context.IntTy; // 'x' and L'x' -> int in C. else if (Literal.isWide()) Ty = Context.WCharTy; // L'x' -> wchar_t in C++. + else if (Literal.isMultiChar()) + Ty = Context.IntTy; // 'wxyz' -> int in C++. else Ty = Context.CharTy; // 'x' -> char in C++ @@ -2029,8 +2067,9 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, Expr *RHSExp = static_cast<Expr*>(Idx.get()); // Perform default conversions. - DefaultFunctionArrayConversion(LHSExp); - DefaultFunctionArrayConversion(RHSExp); + if (!LHSExp->getType()->getAs<VectorType>()) + DefaultFunctionArrayLvalueConversion(LHSExp); + DefaultFunctionArrayLvalueConversion(RHSExp); QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType(); @@ -2072,7 +2111,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, ResultType = VTy->getElementType(); } else if (LHSTy->isArrayType()) { // If we see an array that wasn't promoted by - // DefaultFunctionArrayConversion, it must be an array that + // DefaultFunctionArrayLvalueConversion, it must be an array that // wasn't promoted because of the C90 rule that doesn't // allow promoting non-lvalue arrays. Warn, then // force the promotion here. @@ -2542,7 +2581,11 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, bool Dependent = BaseExprType->isDependentType() || R.isUnresolvableResult() || - UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs); + OverloadExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs); + + // Suppress any lookup-related diagnostics; we'll do these when we + // pick a member. + R.suppressDiagnostics(); UnresolvedMemberExpr *MemExpr = UnresolvedMemberExpr::Create(Context, Dependent, @@ -2552,8 +2595,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, Qualifier, SS.getRange(), MemberName, MemberLoc, TemplateArgs); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - MemExpr->addDecl(*I); + MemExpr->addDecls(R.begin(), R.end()); return Owned(MemExpr); } @@ -3001,7 +3043,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (DiagnoseUseOfDecl(OMD, MemberLoc)) return ExprError(); - return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel, + return Owned(new (Context) ObjCMessageExpr(Context, BaseExpr, Sel, OMD->getResultType(), OMD, OpLoc, MemberLoc, NULL, 0)); @@ -3248,7 +3290,8 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); // Instantiate the expression. - MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD); + MultiLevelTemplateArgumentList ArgList + = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true); InstantiatingTemplate Inst(*this, CallLoc, Param, ArgList.getInnermost().getFlatArgumentList(), @@ -3770,7 +3813,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle, ConversionDecl); - DefaultFunctionArrayConversion(castExpr); + DefaultFunctionArrayLvalueConversion(castExpr); // C99 6.5.4p2: the cast type needs to be void or scalar and the expression // type needs to be scalar. @@ -4807,7 +4850,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // // Suppress this for references: C++ 8.5.3p5. if (!lhsType->isReferenceType()) - DefaultFunctionArrayConversion(rExpr); + DefaultFunctionArrayLvalueConversion(rExpr); Sema::AssignConvertType result = CheckAssignmentConstraints(lhsType, rExpr->getType()); @@ -5690,6 +5733,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_SubObjCPropertySetting: Diag = diag::error_no_subobject_property_setting; break; + case Expr::MLV_SubObjCPropertyGetterSetting: + Diag = diag::error_no_subobject_property_getter_setting; + break; } SourceRange Assign; @@ -5770,7 +5816,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, // C99 6.5.17 QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) { // Comma performs lvalue conversion (C99 6.3.2.1), but not unary conversions. - DefaultFunctionArrayConversion(RHS); + // C++ does not perform this conversion (C++ [expr.comma]p1). + if (!getLangOptions().CPlusPlus) + DefaultFunctionArrayLvalueConversion(RHS); // FIXME: Check that RHS type is complete in C mode (it's legal for it to be // incomplete in C++). @@ -5961,8 +6009,7 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { Diag(OpLoc, diag::err_typecheck_address_of) << "bit-field" << op->getSourceRange(); return QualType(); - } else if (isa<ExtVectorElementExpr>(op) || (isa<ArraySubscriptExpr>(op) && - cast<ArraySubscriptExpr>(op)->getBase()->getType()->isVectorType())){ + } else if (op->refersToVectorElement()) { // The operand cannot be an element of a vector Diag(OpLoc, diag::err_typecheck_address_of) << "vector element" << op->getSourceRange(); @@ -6337,17 +6384,11 @@ Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of // the arguments. - FunctionSet Functions; + UnresolvedSet<16> Functions; OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); - if (OverOp != OO_None) { - if (S) - LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), - Functions); - Expr *Args[2] = { lhs, rhs }; - DeclarationName OpName - = Context.DeclarationNames.getCXXOperatorName(OverOp); - ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions); - } + if (S && OverOp != OO_None) + LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), + Functions); // Build the (potentially-overloaded, potentially-dependent) // binary operation. @@ -6383,7 +6424,7 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType = CheckAddressOfOperand(Input, OpLoc); break; case UnaryOperator::Deref: - DefaultFunctionArrayConversion(Input); + DefaultFunctionArrayLvalueConversion(Input); resultType = CheckIndirectionOperand(Input, OpLoc); break; case UnaryOperator::Plus: @@ -6420,7 +6461,7 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, break; case UnaryOperator::LNot: // logical negation // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5). - DefaultFunctionArrayConversion(Input); + DefaultFunctionArrayLvalueConversion(Input); resultType = Input->getType(); if (resultType->isDependentType()) break; @@ -6456,16 +6497,11 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of // the arguments. - FunctionSet Functions; + UnresolvedSet<16> Functions; OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc); - if (OverOp != OO_None) { - if (S) - LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), - Functions); - DeclarationName OpName - = Context.DeclarationNames.getCXXOperatorName(OverOp); - ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions); - } + if (S && OverOp != OO_None) + LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), + Functions); return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); } @@ -6595,7 +6631,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, // Promote the array so it looks more like a normal array subscript // expression. - DefaultFunctionArrayConversion(Res); + DefaultFunctionArrayLvalueConversion(Res); // C99 6.5.2.1p1 Expr *Idx = static_cast<Expr*>(OC.U.E); @@ -6772,6 +6808,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; return; } + + CurBlock->ReturnType = RetTy; return; } @@ -6792,11 +6830,18 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { // empty arg list, don't push any params. CurBlock->isVariadic = false; } else if (FTI.hasPrototype) { - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) - CurBlock->Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>()); + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { + ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>(); + if (Param->getIdentifier() == 0 && + !Param->isImplicit() && + !Param->isInvalidDecl() && + !getLangOptions().CPlusPlus) + Diag(Param->getLocation(), diag::err_parameter_name_omitted); + CurBlock->Params.push_back(Param); + } CurBlock->isVariadic = FTI.isVariadic; } - CurBlock->TheDecl->setParams(Context, CurBlock->Params.data(), + CurBlock->TheDecl->setParams(CurBlock->Params.data(), CurBlock->Params.size()); CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); @@ -7255,6 +7300,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // FIXME: keep track of references to static functions Function->setUsed(true); + return; } @@ -7390,7 +7436,7 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { DiagnoseAssignmentAsCondition(E); if (!E->isTypeDependent()) { - DefaultFunctionArrayConversion(E); + DefaultFunctionArrayLvalueConversion(E); QualType T = E->getType(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index b004fc3dba72..9eeda54299ae 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -72,18 +72,17 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, if (const RecordType *RecordT = T->getAs<RecordType>()) { CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); // C++ [expr.typeid]p3: + // [...] If the type of the expression is a class type, the class + // shall be completely-defined. + if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid)) + return ExprError(); + + // C++ [expr.typeid]p3: // When typeid is applied to an expression other than an lvalue of a // polymorphic class type [...] [the] expression is an unevaluated // operand. [...] if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) isUnevaluatedOperand = false; - else { - // C++ [expr.typeid]p3: - // [...] If the type of the expression is a class type, the class - // shall be completely-defined. - if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid)) - return ExprError(); - } } // C++ [expr.typeid]p4: @@ -195,7 +194,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, MultiExprArg exprs, SourceLocation *CommaLocs, SourceLocation RParenLoc) { - assert(TypeRep && "Missing type!"); + if (!TypeRep) + return ExprError(); + TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(TypeRep, &TInfo); if (!TInfo) @@ -263,29 +264,18 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, if (NumExprs > 1 || !Record->hasTrivialConstructor() || !Record->hasTrivialDestructor()) { - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - - CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(Ty, move(exprs), - TypeRange.getBegin(), - SourceRange(TypeRange.getBegin(), - RParenLoc), - DeclarationName(), - InitializationKind::CreateDirect(TypeRange.getBegin(), - LParenLoc, - RParenLoc), - ConstructorArgs); - - if (!Constructor) - return ExprError(); - - OwningExprResult Result = - BuildCXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc, - move_arg(ConstructorArgs), RParenLoc); - if (Result.isInvalid()) - return ExprError(); - - return MaybeBindToTemporary(Result.takeAs<Expr>()); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty); + InitializationKind Kind + = NumExprs ? InitializationKind::CreateDirect(TypeRange.getBegin(), + LParenLoc, RParenLoc) + : InitializationKind::CreateValue(TypeRange.getBegin(), + LParenLoc, RParenLoc); + InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + move(exprs)); + + // FIXME: Improve AST representation? + return move(Result); } // Fall through to value-initialize an object of class type that @@ -530,10 +520,13 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, PlacementArgs.release(); ConstructorArgs.release(); ArraySizeE.release(); - return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, - NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init, - ConsArgs, NumConsArgs, OperatorDelete, ResultType, - StartLoc, Init ? ConstructorRParen : SourceLocation())); + return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, + PlaceArgs, NumPlaceArgs, ParenTypeId, + ArraySize, Constructor, Init, + ConsArgs, NumConsArgs, OperatorDelete, + ResultType, StartLoc, + Init ? ConstructorRParen : + SourceLocation())); } /// CheckAllocatedType - Checks that a type is suitable as the allocated type @@ -636,19 +629,24 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // FIXME: handle ambiguity - OverloadCandidateSet Candidates; + OverloadCandidateSet Candidates(StartLoc); for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. - if (FunctionDecl *Fn = - dyn_cast<FunctionDecl>((*Alloc)->getUnderlyingDecl())) { - AddOverloadCandidate(Fn, Args, NumArgs, Candidates, - /*SuppressUserConversions=*/false); + + if (FunctionTemplateDecl *FnTemplate = + dyn_cast<FunctionTemplateDecl>((*Alloc)->getUnderlyingDecl())) { + AddTemplateOverloadCandidate(FnTemplate, Alloc.getAccess(), + /*ExplicitTemplateArgs=*/0, Args, NumArgs, + Candidates, + /*SuppressUserConversions=*/false); continue; - } - - // FIXME: Handle function templates + } + + FunctionDecl *Fn = cast<FunctionDecl>((*Alloc)->getUnderlyingDecl()); + AddOverloadCandidate(Fn, Alloc.getAccess(), Args, NumArgs, Candidates, + /*SuppressUserConversions=*/false); } // Do the resolution. @@ -779,12 +777,16 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, DeclContext::lookup_iterator Alloc, AllocEnd; for (llvm::tie(Alloc, AllocEnd) = GlobalCtx->lookup(Name); Alloc != AllocEnd; ++Alloc) { - // FIXME: Do we need to check for default arguments here? - FunctionDecl *Func = cast<FunctionDecl>(*Alloc); - if (Func->getNumParams() == 1 && + // Only look at non-template functions, as it is the predefined, + // non-templated allocation function we are trying to declare here. + if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*Alloc)) { + QualType InitialParamType = Context.getCanonicalType( - Func->getParamDecl(0)->getType().getUnqualifiedType()) == Argument) - return; + Func->getParamDecl(0)->getType().getUnqualifiedType()); + // FIXME: Do we need to check for default arguments here? + if (Func->getNumParams() == 1 && InitialParamType == Argument) + return; + } } } @@ -812,7 +814,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), 0, Argument, /*TInfo=*/0, VarDecl::None, 0); - Alloc->setParams(Context, &Param, 1); + Alloc->setParams(&Param, 1); // FIXME: Also add this declaration to the IdentifierResolver, but // make sure it is at the end of the chain to coincide with the @@ -1487,9 +1489,9 @@ QualType Sema::CheckPointerToMemberOperands( static QualType TargetType(const ImplicitConversionSequence &ICS) { switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: - return ICS.Standard.getToType(); + return ICS.Standard.getToType(2); case ImplicitConversionSequence::UserDefinedConversion: - return ICS.UserDefined.After.getToType(); + return ICS.UserDefined.After.getToType(2); case ImplicitConversionSequence::AmbiguousConversion: return ICS.Ambiguous.getToType(); case ImplicitConversionSequence::EllipsisConversion: @@ -1587,7 +1589,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, SourceLocation Loc) { Expr *Args[2] = { LHS, RHS }; - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(Loc); Self.AddBuiltinOperatorCandidates(OO_Conditional, Loc, Args, 2, CandidateSet); OverloadCandidateSet::iterator Best; @@ -1689,8 +1691,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LVoid || RVoid) { // ... then the [l2r] conversions are performed on the second and third // operands ... - DefaultFunctionArrayConversion(LHS); - DefaultFunctionArrayConversion(RHS); + DefaultFunctionArrayLvalueConversion(LHS); + DefaultFunctionArrayLvalueConversion(RHS); LTy = LHS->getType(); RTy = RHS->getType(); @@ -1776,8 +1778,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // C++0x 5.16p6 // LValue-to-rvalue, array-to-pointer, and function-to-pointer standard // conversions are performed on the second and third operands. - DefaultFunctionArrayConversion(LHS); - DefaultFunctionArrayConversion(RHS); + DefaultFunctionArrayLvalueConversion(LHS); + DefaultFunctionArrayLvalueConversion(RHS); LTy = LHS->getType(); RTy = RHS->getType(); @@ -1987,10 +1989,8 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!RT) return Owned(E); - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialDestructor()) - return Owned(E); - + // If this is the result of a call expression, our source might + // actually be a reference, in which case we shouldn't bind. if (CallExpr *CE = dyn_cast<CallExpr>(E)) { QualType Ty = CE->getCallee()->getType(); if (const PointerType *PT = Ty->getAs<PointerType>()) @@ -2000,6 +2000,13 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { if (FTy->getResultType()->isReferenceType()) return Owned(E); } + + // That should be enough to guarantee that this type is complete. + // If it has a trivial destructor, we can avoid the extra copy. + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialDestructor()) + return Owned(E); + CXXTemporary *Temp = CXXTemporary::Create(Context, RD->getDestructor(Context)); ExprTemporaries.push_back(Temp); diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index ea8f4e3e890f..0c5d8efa288b 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -470,11 +470,13 @@ Sema::ExprResult Sema::ActOnClassMessage( // now, we simply pass the "super" identifier through (which isn't consistent // with instance methods. if (isSuper) - return new (Context) ObjCMessageExpr(receiverName, Sel, returnType, Method, - lbrac, rbrac, ArgExprs, NumArgs); + return new (Context) ObjCMessageExpr(Context, receiverName, Sel, returnType, + Method, lbrac, rbrac, ArgExprs, + NumArgs); else - return new (Context) ObjCMessageExpr(ClassDecl, Sel, returnType, Method, - lbrac, rbrac, ArgExprs, NumArgs); + return new (Context) ObjCMessageExpr(Context, ClassDecl, Sel, returnType, + Method, lbrac, rbrac, ArgExprs, + NumArgs); } // ActOnInstanceMessage - used for both unary and keyword messages. @@ -492,7 +494,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. - DefaultFunctionArrayConversion(RExpr); + DefaultFunctionArrayLvalueConversion(RExpr); QualType returnType; QualType ReceiverCType = @@ -521,8 +523,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, return true; returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, - rbrac, ArgExprs, NumArgs); + return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, + Method, lbrac, rbrac, + ArgExprs, NumArgs); } // Handle messages to id. @@ -536,8 +539,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, lbrac, rbrac, returnType)) return true; returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, - rbrac, ArgExprs, NumArgs); + return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, + Method, lbrac, rbrac, + ArgExprs, NumArgs); } // Handle messages to Class. @@ -582,8 +586,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, lbrac, rbrac, returnType)) return true; returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, - rbrac, ArgExprs, NumArgs); + return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, + Method, lbrac, rbrac, + ArgExprs, NumArgs); } ObjCMethodDecl *Method = 0; @@ -665,7 +670,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, lbrac, rbrac, returnType)) return true; returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, - rbrac, ArgExprs, NumArgs); + return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, Method, + lbrac, rbrac, ArgExprs, NumArgs); } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index fd62e1afce4f..7b4a41777b6a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -66,40 +66,6 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) { return 0; } -static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, - bool DirectInit, Sema &S) { - // Get the type before calling CheckSingleAssignmentConstraints(), since - // it can promote the expression. - QualType InitType = Init->getType(); - - if (S.getLangOptions().CPlusPlus) { - // FIXME: I dislike this error message. A lot. - if (S.PerformImplicitConversion(Init, DeclType, - Sema::AA_Initializing, DirectInit)) { - ImplicitConversionSequence ICS; - OverloadCandidateSet CandidateSet; - if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined, - CandidateSet, - true, false, false) != OR_Ambiguous) - return S.Diag(Init->getSourceRange().getBegin(), - diag::err_typecheck_convert_incompatible) - << DeclType << Init->getType() << Sema::AA_Initializing - << Init->getSourceRange(); - S.Diag(Init->getSourceRange().getBegin(), - diag::err_typecheck_convert_ambiguous) - << DeclType << Init->getType() << Init->getSourceRange(); - S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, &Init, 1); - return true; - } - return false; - } - - Sema::AssignConvertType ConvTy = - S.CheckSingleAssignmentConstraints(DeclType, Init); - return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType, - InitType, Init, Sema::AA_Initializing); -} - static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { // Get the length of the string as parsed. uint64_t StrLength = @@ -174,47 +140,57 @@ class InitListChecker { std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic; InitListExpr *FullyStructuredList; - void CheckImplicitInitList(InitListExpr *ParentIList, QualType T, + void CheckImplicitInitList(const InitializedEntity &Entity, + InitListExpr *ParentIList, QualType T, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject = false); - void CheckExplicitInitList(InitListExpr *IList, QualType &T, + void CheckExplicitInitList(const InitializedEntity &Entity, + InitListExpr *IList, QualType &T, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject = false); - void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, + void CheckListElementTypes(const InitializedEntity &Entity, + InitListExpr *IList, QualType &DeclType, bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject = false); - void CheckSubElementType(InitListExpr *IList, QualType ElemType, + void CheckSubElementType(const InitializedEntity &Entity, + InitListExpr *IList, QualType ElemType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); - void CheckScalarType(InitListExpr *IList, QualType DeclType, + void CheckScalarType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); - void CheckReferenceType(InitListExpr *IList, QualType DeclType, + void CheckReferenceType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); - void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index, + void CheckVectorType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); - void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, + void CheckStructUnionTypes(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, RecordDecl::field_iterator Field, bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject = false); - void CheckArrayType(InitListExpr *IList, QualType &DeclType, + void CheckArrayType(const InitializedEntity &Entity, + InitListExpr *IList, QualType &DeclType, llvm::APSInt elementIndex, bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); - bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE, + bool CheckDesignatedInitializer(const InitializedEntity &Entity, + InitListExpr *IList, DesignatedInitExpr *DIE, unsigned DesigIdx, QualType &CurrentObjectType, RecordDecl::field_iterator *NextField, @@ -433,7 +409,8 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, unsigned newStructuredIndex = 0; FullyStructuredList = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange()); - CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex, + CheckExplicitInitList(Entity, IL, T, newIndex, + FullyStructuredList, newStructuredIndex, /*TopLevelObject=*/true); if (!hadError) { @@ -470,7 +447,8 @@ int InitListChecker::numStructUnionElements(QualType DeclType) { return InitializableMembers - structDecl->hasFlexibleArrayMember(); } -void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, +void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, + InitListExpr *ParentIList, QualType T, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, @@ -504,7 +482,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, // Check the element types and build the structural subobject. unsigned StartIndex = Index; - CheckListElementTypes(ParentIList, T, false, Index, + CheckListElementTypes(Entity, ParentIList, T, + /*SubobjectIsDesignatorContext=*/false, Index, StructuredSubobjectInitList, StructuredSubobjectInitIndex, TopLevelObject); @@ -520,7 +499,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, } } -void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, +void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, + InitListExpr *IList, QualType &T, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, @@ -528,10 +508,10 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); SyntacticToSemantic[IList] = StructuredList; StructuredList->setSyntacticForm(IList); - CheckListElementTypes(IList, T, true, Index, StructuredList, - StructuredIndex, TopLevelObject); - IList->setType(T); - StructuredList->setType(T); + CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, + Index, StructuredList, StructuredIndex, TopLevelObject); + IList->setType(T.getNonReferenceType()); + StructuredList->setType(T.getNonReferenceType()); if (hadError) return; @@ -580,7 +560,8 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, << CodeModificationHint::CreateRemoval(IList->getLocEnd()); } -void InitListChecker::CheckListElementTypes(InitListExpr *IList, +void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, + InitListExpr *IList, QualType &DeclType, bool SubobjectIsDesignatorContext, unsigned &Index, @@ -588,13 +569,15 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList, unsigned &StructuredIndex, bool TopLevelObject) { if (DeclType->isScalarType()) { - CheckScalarType(IList, DeclType, Index, StructuredList, StructuredIndex); + CheckScalarType(Entity, IList, DeclType, Index, + StructuredList, StructuredIndex); } else if (DeclType->isVectorType()) { - CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex); + CheckVectorType(Entity, IList, DeclType, Index, + StructuredList, StructuredIndex); } else if (DeclType->isAggregateType()) { if (DeclType->isRecordType()) { RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); - CheckStructUnionTypes(IList, DeclType, RD->field_begin(), + CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(), SubobjectIsDesignatorContext, Index, StructuredList, StructuredIndex, TopLevelObject); @@ -602,7 +585,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList, llvm::APSInt Zero( SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()), false); - CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index, + CheckArrayType(Entity, IList, DeclType, Zero, + SubobjectIsDesignatorContext, Index, StructuredList, StructuredIndex); } else assert(0 && "Aggregate that isn't a structure or array?!"); @@ -625,7 +609,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList, << DeclType << IList->getSourceRange(); hadError = true; } else if (DeclType->isReferenceType()) { - CheckReferenceType(IList, DeclType, Index, StructuredList, StructuredIndex); + CheckReferenceType(Entity, IList, DeclType, Index, + StructuredList, StructuredIndex); } else { // In C, all types are either scalars or aggregates, but // additional handling is needed here for C++ (and possibly others?). @@ -633,7 +618,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList, } } -void InitListChecker::CheckSubElementType(InitListExpr *IList, +void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, + InitListExpr *IList, QualType ElemType, unsigned &Index, InitListExpr *StructuredList, @@ -646,7 +632,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, = getStructuredSubobjectInit(IList, Index, ElemType, StructuredList, StructuredIndex, SubInitList->getSourceRange()); - CheckExplicitInitList(SubInitList, ElemType, newIndex, + CheckExplicitInitList(Entity, SubInitList, ElemType, newIndex, newStructuredList, newStructuredIndex); ++StructuredIndex; ++Index; @@ -655,9 +641,11 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, UpdateStructuredListElement(StructuredList, StructuredIndex, Str); ++Index; } else if (ElemType->isScalarType()) { - CheckScalarType(IList, ElemType, Index, StructuredList, StructuredIndex); + CheckScalarType(Entity, IList, ElemType, Index, + StructuredList, StructuredIndex); } else if (ElemType->isReferenceType()) { - CheckReferenceType(IList, ElemType, Index, StructuredList, StructuredIndex); + CheckReferenceType(Entity, IList, ElemType, Index, + StructuredList, StructuredIndex); } else { if (SemaRef.getLangOptions().CPlusPlus) { // C++ [dcl.init.aggr]p12: @@ -665,17 +653,21 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, // initializing the aggregate member with an ini- tializer from // an initializer-list. If the initializer can initialize a // member, the member is initialized. [...] - ImplicitConversionSequence ICS - = SemaRef.TryCopyInitialization(expr, ElemType, - /*SuppressUserConversions=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - - if (!ICS.isBad()) { - if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS, - Sema::AA_Initializing)) + + // FIXME: Better EqualLoc? + InitializationKind Kind = + InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation()); + InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1); + + if (Seq) { + Sema::OwningExprResult Result = + Seq.Perform(SemaRef, Entity, Kind, + Sema::MultiExprArg(SemaRef, (void **)&expr, 1)); + if (Result.isInvalid()) hadError = true; - UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + + UpdateStructuredListElement(StructuredList, StructuredIndex, + Result.takeAs<Expr>()); ++Index; return; } @@ -707,13 +699,15 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, // considered for the initialization of the first member of // the subaggregate. if (ElemType->isAggregateType() || ElemType->isVectorType()) { - CheckImplicitInitList(IList, ElemType, Index, StructuredList, + CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList, StructuredIndex); ++StructuredIndex; } else { // We cannot initialize this element, so let // PerformCopyInitialization produce the appropriate diagnostic. - SemaRef.PerformCopyInitialization(expr, ElemType, Sema::AA_Initializing); + SemaRef.PerformCopyInitialization(Entity, SourceLocation(), + SemaRef.Owned(expr)); + IList->setInit(Index, 0); hadError = true; ++Index; ++StructuredIndex; @@ -721,7 +715,8 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, } } -void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType, +void InitListChecker::CheckScalarType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { @@ -745,17 +740,26 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType, return; } - Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer. - if (CheckSingleInitializer(expr, DeclType, false, SemaRef)) + Sema::OwningExprResult Result = + SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), + SemaRef.Owned(expr)); + + Expr *ResultExpr = 0; + + if (Result.isInvalid()) hadError = true; // types weren't compatible. - else if (savExpr != expr) { - // The type was promoted, update initializer list. - IList->setInit(Index, expr); + else { + ResultExpr = Result.takeAs<Expr>(); + + if (ResultExpr != expr) { + // The type was promoted, update initializer list. + IList->setInit(Index, ResultExpr); + } } if (hadError) ++StructuredIndex; else - UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr); ++Index; } else { SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer) @@ -767,7 +771,8 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType, } } -void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType, +void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { @@ -782,17 +787,16 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType, return; } - Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer. - if (SemaRef.CheckReferenceInit(expr, DeclType, - /*FIXME:*/expr->getLocStart(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false)) + Sema::OwningExprResult Result = + SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), + SemaRef.Owned(expr)); + + if (Result.isInvalid()) hadError = true; - else if (savExpr != expr) { - // The type was promoted, update initializer list. - IList->setInit(Index, expr); - } + + expr = Result.takeAs<Expr>(); + IList->setInit(Index, expr); + if (hadError) ++StructuredIndex; else @@ -814,7 +818,8 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType, } } -void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, +void InitListChecker::CheckVectorType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { @@ -825,22 +830,33 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, QualType elementType = VT->getElementType(); if (!SemaRef.getLangOptions().OpenCL) { + InitializedEntity ElementEntity = + InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); + for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) { // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) break; - CheckSubElementType(IList, elementType, Index, + + ElementEntity.setElementIndex(Index); + CheckSubElementType(ElementEntity, IList, elementType, Index, StructuredList, StructuredIndex); } } else { + InitializedEntity ElementEntity = + InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); + // OpenCL initializers allows vectors to be constructed from vectors. for (unsigned i = 0; i < maxElements; ++i) { // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) break; + + ElementEntity.setElementIndex(Index); + QualType IType = IList->getInit(Index)->getType(); if (!IType->isVectorType()) { - CheckSubElementType(IList, elementType, Index, + CheckSubElementType(ElementEntity, IList, elementType, Index, StructuredList, StructuredIndex); ++numEltsInit; } else { @@ -848,7 +864,7 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned numIElts = IVT->getNumElements(); QualType VecType = SemaRef.Context.getExtVectorType(elementType, numIElts); - CheckSubElementType(IList, VecType, Index, + CheckSubElementType(ElementEntity, IList, VecType, Index, StructuredList, StructuredIndex); numEltsInit += numIElts; } @@ -864,7 +880,8 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, } } -void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, +void InitListChecker::CheckArrayType(const InitializedEntity &Entity, + InitListExpr *IList, QualType &DeclType, llvm::APSInt elementIndex, bool SubobjectIsDesignatorContext, unsigned &Index, @@ -925,7 +942,7 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, // Handle this designated initializer. elementIndex will be // updated to be the next array element we'll initialize. - if (CheckDesignatedInitializer(IList, DIE, 0, + if (CheckDesignatedInitializer(Entity, IList, DIE, 0, DeclType, 0, &elementIndex, Index, StructuredList, StructuredIndex, true, false)) { @@ -952,8 +969,11 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, if (maxElementsKnown && elementIndex == maxElements) break; + InitializedEntity ElementEntity = + InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex, + Entity); // Check this element. - CheckSubElementType(IList, elementType, Index, + CheckSubElementType(ElementEntity, IList, elementType, Index, StructuredList, StructuredIndex); ++elementIndex; @@ -978,7 +998,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, } } -void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, +void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, RecordDecl::field_iterator Field, bool SubobjectIsDesignatorContext, @@ -1027,7 +1048,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, // Handle this designated initializer. Field will be updated to // the next field that we'll be initializing. - if (CheckDesignatedInitializer(IList, DIE, 0, + if (CheckDesignatedInitializer(Entity, IList, DIE, 0, DeclType, &Field, 0, Index, StructuredList, StructuredIndex, true, TopLevelObject)) @@ -1056,7 +1077,9 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, continue; } - CheckSubElementType(IList, Field->getType(), Index, + InitializedEntity MemberEntity = + InitializedEntity::InitializeMember(*Field, &Entity); + CheckSubElementType(MemberEntity, IList, Field->getType(), Index, StructuredList, StructuredIndex); InitializedSomething = true; @@ -1092,12 +1115,15 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, << *Field; } + InitializedEntity MemberEntity = + InitializedEntity::InitializeMember(*Field, &Entity); + if (isa<InitListExpr>(IList->getInit(Index))) - CheckSubElementType(IList, Field->getType(), Index, StructuredList, - StructuredIndex); + CheckSubElementType(MemberEntity, IList, Field->getType(), Index, + StructuredList, StructuredIndex); else - CheckImplicitInitList(IList, Field->getType(), Index, StructuredList, - StructuredIndex); + CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index, + StructuredList, StructuredIndex); } /// \brief Expand a field designator that refers to a member of an @@ -1194,7 +1220,8 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, /// /// @returns true if there was an error, false otherwise. bool -InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, +InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, + InitListExpr *IList, DesignatedInitExpr *DIE, unsigned DesigIdx, QualType &CurrentObjectType, @@ -1215,7 +1242,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, unsigned OldIndex = Index; IList->setInit(OldIndex, DIE->getInit()); - CheckSubElementType(IList, CurrentObjectType, Index, + CheckSubElementType(Entity, IList, CurrentObjectType, Index, StructuredList, StructuredIndex); // Restore the designated initializer expression in the syntactic @@ -1423,8 +1450,12 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, unsigned newStructuredIndex = FieldIndex; unsigned OldIndex = Index; IList->setInit(Index, DIE->getInit()); - CheckSubElementType(IList, Field->getType(), Index, + + InitializedEntity MemberEntity = + InitializedEntity::InitializeMember(*Field, &Entity); + CheckSubElementType(MemberEntity, IList, Field->getType(), Index, StructuredList, newStructuredIndex); + IList->setInit(OldIndex, DIE); if (hadError && !prevHadError) { ++Field; @@ -1438,8 +1469,12 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // Recurse to check later designated subobjects. QualType FieldType = (*Field)->getType(); unsigned newStructuredIndex = FieldIndex; - if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, FieldType, 0, 0, - Index, StructuredList, newStructuredIndex, + + InitializedEntity MemberEntity = + InitializedEntity::InitializeMember(*Field, &Entity); + if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1, + FieldType, 0, 0, Index, + StructuredList, newStructuredIndex, true, false)) return true; } @@ -1467,7 +1502,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // Check the remaining fields within this class/struct/union subobject. bool prevHadError = hadError; - CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index, + + CheckStructUnionTypes(Entity, IList, CurrentObjectType, Field, false, Index, StructuredList, FieldIndex); return hadError && !prevHadError; } @@ -1552,12 +1588,19 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // Move to the next designator unsigned ElementIndex = DesignatedStartIndex.getZExtValue(); unsigned OldIndex = Index; + + InitializedEntity ElementEntity = + InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); + while (DesignatedStartIndex <= DesignatedEndIndex) { // Recurse to check later designated subobjects. QualType ElementType = AT->getElementType(); Index = OldIndex; - if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, ElementType, 0, 0, - Index, StructuredList, ElementIndex, + + ElementEntity.setElementIndex(ElementIndex); + if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1, + ElementType, 0, 0, Index, + StructuredList, ElementIndex, (DesignatedStartIndex == DesignatedEndIndex), false)) return true; @@ -1581,7 +1624,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, // Check the remaining elements within this array subobject. bool prevHadError = hadError; - CheckArrayType(IList, CurrentObjectType, DesignatedStartIndex, false, Index, + CheckArrayType(Entity, IList, CurrentObjectType, DesignatedStartIndex, + /*SubobjectIsDesignatorContext=*/false, Index, StructuredList, ElementIndex); return hadError && !prevHadError; } @@ -1628,7 +1672,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0, InitRange.getEnd()); - Result->setType(CurrentObjectType); + Result->setType(CurrentObjectType.getNonReferenceType()); // Pre-allocate storage for the structured initializer list. unsigned NumElements = 0; @@ -1927,7 +1971,8 @@ void InitializationSequence::AddAddressOverloadResolutionStep( Step S; S.Kind = SK_ResolveAddressOfOverloadedFunction; S.Type = Function->getType(); - S.Function = Function; + // Access is currently ignored for these. + S.Function = DeclAccessPair::make(Function, AccessSpecifier(0)); Steps.push_back(S); } @@ -1948,11 +1993,12 @@ void InitializationSequence::AddReferenceBindingStep(QualType T, } void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, + AccessSpecifier Access, QualType T) { Step S; S.Kind = SK_UserConversion; S.Type = T; - S.Function = Function; + S.Function = DeclAccessPair::make(Function, Access); Steps.push_back(S); } @@ -1985,11 +2031,12 @@ void InitializationSequence::AddListInitializationStep(QualType T) { void InitializationSequence::AddConstructorInitializationStep( CXXConstructorDecl *Constructor, + AccessSpecifier Access, QualType T) { Step S; S.Kind = SK_ConstructorInitialization; S.Type = T; - S.Function = Constructor; + S.Function = DeclAccessPair::make(Constructor, Access); Steps.push_back(S); } @@ -2129,10 +2176,13 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + S.AddTemplateOverloadCandidate(ConstructorTmpl, + ConstructorTmpl->getAccess(), + /*ExplicitArgs*/ 0, &Initializer, 1, CandidateSet); else - S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet); + S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + &Initializer, 1, CandidateSet); } } } @@ -2172,11 +2222,12 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, if ((AllowExplicit || !Conv->isExplicit()) && (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){ if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer, + S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), + ActingDC, Initializer, ToType, CandidateSet); else - S.AddConversionCandidate(Conv, ActingDC, Initializer, cv1T1, - CandidateSet); + S.AddConversionCandidate(Conv, I.getAccess(), ActingDC, + Initializer, cv1T1, CandidateSet); } } } @@ -2198,7 +2249,8 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, T2 = cv1T1; // Add the user-defined conversion step. - Sequence.AddUserConversionStep(Function, T2.getNonReferenceType()); + Sequence.AddUserConversionStep(Function, Best->getAccess(), + T2.getNonReferenceType()); // Determine whether we need to perform derived-to-base or // cv-qualification adjustments. @@ -2281,16 +2333,20 @@ static void TryReferenceInitialization(Sema &S, // - is an lvalue (but is not a bit-field), and "cv1 T1" is // reference-compatible with "cv2 T2," or // - // Per C++ [over.best.ics]p2, we ignore whether the lvalue is a + // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a // bit-field when we're determining whether the reference initialization - // can occur. This property will be checked by PerformInitialization. + // can occur. However, we do pay attention to whether it is a bit-field + // to decide whether we're actually binding to a temporary created from + // the bit-field. if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( S.Context.getQualifiedType(T1, T2Quals), /*isLValue=*/true); if (T1Quals != T2Quals) Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true); - Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false); + bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() && + (Initializer->getBitField() || Initializer->refersToVectorElement()); + Sequence.AddReferenceBindingStep(cv1T1, BindingTemporary); return; } @@ -2319,7 +2375,7 @@ static void TryReferenceInitialization(Sema &S, // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference and the initializer expression shall // be an rvalue. - if (!((isLValueRef && T1Quals.hasConst()) || + if (!((isLValueRef && T1Quals.hasConst() && !T1Quals.hasVolatile()) || (isRValueRef && InitLvalue != Expr::LV_Valid))) { if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) Sequence.SetOverloadFailure( @@ -2489,10 +2545,13 @@ static void TryConstructorInitialization(Sema &S, if (!Constructor->isInvalidDecl() && (AllowExplicit || !Constructor->isExplicit())) { if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + S.AddTemplateOverloadCandidate(ConstructorTmpl, + ConstructorTmpl->getAccess(), + /*ExplicitArgs*/ 0, Args, NumArgs, CandidateSet); else - S.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + Args, NumArgs, CandidateSet); } } @@ -2507,14 +2566,26 @@ static void TryConstructorInitialization(Sema &S, Result); return; } - + + // C++0x [dcl.init]p6: + // If a program calls for the default initialization of an object + // of a const-qualified type T, T shall be a class type with a + // user-provided default constructor. + if (Kind.getKind() == InitializationKind::IK_Default && + Entity.getType().isConstQualified() && + cast<CXXConstructorDecl>(Best->Function)->isImplicit()) { + Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); + return; + } + // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. if (Kind.getKind() == InitializationKind::IK_Copy) { - Sequence.AddUserConversionStep(Best->Function, DestType); + Sequence.AddUserConversionStep(Best->Function, Best->getAccess(), DestType); } else { Sequence.AddConstructorInitializationStep( cast<CXXConstructorDecl>(Best->Function), + Best->getAccess(), DestType); } } @@ -2579,10 +2650,7 @@ static void TryDefaultInitialization(Sema &S, // - if T is a (possibly cv-qualified) class type (Clause 9), the default // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); - if (DestType->isRecordType()) { - // FIXME: If a program calls for the default initialization of an object of - // a const-qualified type T, T shall be a class type with a user-provided - // default constructor. + if (DestType->isRecordType() && S.getLangOptions().CPlusPlus) { return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, Sequence); } @@ -2593,7 +2661,7 @@ static void TryDefaultInitialization(Sema &S, // If a program calls for the default initialization of an object of // a const-qualified type T, T shall be a class type with a user-provided // default constructor. - if (DestType.isConstQualified()) + if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); } @@ -2647,10 +2715,13 @@ static void TryUserDefinedConversion(Sema &S, if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + S.AddTemplateOverloadCandidate(ConstructorTmpl, + ConstructorTmpl->getAccess(), + /*ExplicitArgs*/ 0, &Initializer, 1, CandidateSet); else - S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet); + S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + &Initializer, 1, CandidateSet); } } } @@ -2686,12 +2757,12 @@ static void TryUserDefinedConversion(Sema &S, if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, - Initializer, DestType, + S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), + ActingDC, Initializer, DestType, CandidateSet); else - S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType, - CandidateSet); + S.AddConversionCandidate(Conv, I.getAccess(), ActingDC, + Initializer, DestType, CandidateSet); } } } @@ -2712,13 +2783,13 @@ static void TryUserDefinedConversion(Sema &S, if (isa<CXXConstructorDecl>(Function)) { // Add the user-defined conversion step. Any cv-qualification conversion is // subsumed by the initialization. - Sequence.AddUserConversionStep(Function, DestType); + Sequence.AddUserConversionStep(Function, Best->getAccess(), DestType); return; } // Add the user-defined conversion step that calls the conversion function. QualType ConvType = Function->getResultType().getNonReferenceType(); - Sequence.AddUserConversionStep(Function, ConvType); + Sequence.AddUserConversionStep(Function, Best->getAccess(), ConvType); // If the conversion following the call to the conversion function is // interesting, add it as a separate step. @@ -2758,7 +2829,8 @@ InitializationSequence::InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr **Args, - unsigned NumArgs) { + unsigned NumArgs) + : FailedCandidateSet(Kind.getLocation()) { ASTContext &Context = S.Context; // C++0x [dcl.init]p16: @@ -2934,15 +3006,15 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity, bool IsCopy) { switch (Entity.getKind()) { case InitializedEntity::EK_Result: - case InitializedEntity::EK_Exception: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_Member: return !IsCopy; case InitializedEntity::EK_New: case InitializedEntity::EK_Variable: case InitializedEntity::EK_Base: - case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_Exception: return false; case InitializedEntity::EK_Parameter: @@ -2960,6 +3032,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Sema::OwningExprResult CurInit) { + Expr *CurInitExpr = (Expr *)CurInit.get(); + SourceLocation Loc; switch (Entity.getKind()) { @@ -2980,6 +3054,14 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, Loc = Entity.getDecl()->getLocation(); break; + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_Member: + if (Entity.getType()->isReferenceType() || + Kind.getKind() != InitializationKind::IK_Copy) + return move(CurInit); + Loc = CurInitExpr->getLocStart(); + break; + case InitializedEntity::EK_Parameter: // FIXME: Do we need this initialization for a parameter? return move(CurInit); @@ -2987,14 +3069,11 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, case InitializedEntity::EK_New: case InitializedEntity::EK_Temporary: case InitializedEntity::EK_Base: - case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: // We don't need to copy for any of these initialized entities. return move(CurInit); } - Expr *CurInitExpr = (Expr *)CurInit.get(); CXXRecordDecl *Class = 0; if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>()) Class = cast<CXXRecordDecl>(Record->getDecl()); @@ -3006,7 +3085,7 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, = S.Context.DeclarationNames.getCXXConstructorName( S.Context.getCanonicalType(S.Context.getTypeDeclType(Class))); DeclContext::lookup_iterator Con, ConEnd; - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(Loc); for (llvm::tie(Con, ConEnd) = Class->lookup(ConstructorName); Con != ConEnd; ++Con) { // Find the constructor (which may be a template). @@ -3015,7 +3094,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, !Constructor->isCopyConstructor()) continue; - S.AddOverloadCandidate(Constructor, &CurInitExpr, 1, CandidateSet); + S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + &CurInitExpr, 1, CandidateSet); } OverloadCandidateSet::iterator Best; @@ -3111,6 +3191,9 @@ InitializationSequence::Perform(Sema &S, if (Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast()) return Sema::OwningExprResult(S, Args.release()[0]); + if (Args.size() == 0) + return S.Owned((Expr *)0); + unsigned NumArgs = Args.size(); return S.Owned(new (S.Context) ParenListExpr(S.Context, SourceLocation(), @@ -3176,7 +3259,9 @@ InitializationSequence::Perform(Sema &S, case SK_ResolveAddressOfOverloadedFunction: // Overload resolution determined which function invoke; update the // initializer to reflect that choice. - CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function); + // Access control was done in overload resolution. + CurInit = S.FixOverloadedFunctionReference(move(CurInit), + cast<FunctionDecl>(Step->Function.getDecl())); break; case SK_CastDerivedToBaseRValue: @@ -3209,21 +3294,30 @@ InitializationSequence::Perform(Sema &S, S.Diag(BitField->getLocation(), diag::note_bitfield_decl); return S.ExprError(); } + + if (CurInitExpr->refersToVectorElement()) { + // References cannot bind to vector elements. + S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element) + << Entity.getType().isVolatileQualified() + << CurInitExpr->getSourceRange(); + return S.ExprError(); + } // Reference binding does not have any corresponding ASTs. // Check exception specifications if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) return S.ExprError(); + break; - + case SK_BindReferenceToTemporary: + // Reference binding does not have any corresponding ASTs. + // Check exception specifications if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) return S.ExprError(); - // FIXME: At present, we have no AST to describe when we need to make a - // temporary to bind a reference to. We should. break; case SK_UserConversion: { @@ -3231,13 +3325,14 @@ InitializationSequence::Perform(Sema &S, // or a conversion function. CastExpr::CastKind CastKind = CastExpr::CK_Unknown; bool IsCopy = false; - if (CXXConstructorDecl *Constructor - = dyn_cast<CXXConstructorDecl>(Step->Function)) { + FunctionDecl *Fn = cast<FunctionDecl>(Step->Function.getDecl()); + AccessSpecifier FnAccess = Step->Function.getAccess(); + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); SourceLocation Loc = CurInitExpr->getLocStart(); CurInit.release(); // Ownership transferred into MultiExprArg, below. - + // Determine the arguments required to actually perform the constructor // call. if (S.CompleteConstructorCall(Constructor, @@ -3252,6 +3347,8 @@ InitializationSequence::Perform(Sema &S, move_arg(ConstructorArgs)); if (CurInit.isInvalid()) return S.ExprError(); + + S.CheckConstructorAccess(Kind.getLocation(), Constructor, FnAccess); CastKind = CastExpr::CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); @@ -3260,8 +3357,11 @@ InitializationSequence::Perform(Sema &S, IsCopy = true; } else { // Build a call to the conversion function. - CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function); + CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); + S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, + Conversion, FnAccess); + // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because // we don't want to turn off access control here for c-style casts. @@ -3326,8 +3426,8 @@ InitializationSequence::Perform(Sema &S, case SK_ConstructorInitialization: { CXXConstructorDecl *Constructor - = cast<CXXConstructorDecl>(Step->Function); - + = cast<CXXConstructorDecl>(Step->Function.getDecl()); + // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); SourceLocation Loc = Kind.getLocation(); @@ -3342,9 +3442,13 @@ InitializationSequence::Perform(Sema &S, CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), Constructor, move_arg(ConstructorArgs), - ConstructorInitRequiresZeroInit); + ConstructorInitRequiresZeroInit, + Entity.getKind() == InitializedEntity::EK_Base); if (CurInit.isInvalid()) return S.ExprError(); + + // Only check access if all of that succeeded. + S.CheckConstructorAccess(Loc, Constructor, Step->Function.getAccess()); bool Elidable = cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable(); @@ -3422,8 +3526,13 @@ bool InitializationSequence::Diagnose(Sema &S, QualType DestType = Entity.getType(); switch (Failure) { case FK_TooManyInitsForReference: - S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) - << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); + // FIXME: Customize for the initialized entity? + if (NumArgs == 0) + S.Diag(Kind.getLocation(), diag::err_reference_without_init) + << DestType.getNonReferenceType(); + else // FIXME: diagnostic below could be better! + S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) + << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); break; case FK_ArrayNeedsInitList: @@ -3492,6 +3601,7 @@ bool InitializationSequence::Diagnose(Sema &S, Failure == FK_NonConstLValueReferenceBindingToTemporary ? diag::err_lvalue_reference_bind_to_temporary : diag::err_lvalue_reference_bind_to_unrelated) + << DestType.getNonReferenceType().isVolatileQualified() << DestType.getNonReferenceType() << Args[0]->getType() << Args[0]->getSourceRange(); @@ -3567,6 +3677,45 @@ bool InitializationSequence::Diagnose(Sema &S, break; case OR_No_Viable_Function: + if (Kind.getKind() == InitializationKind::IK_Default && + (Entity.getKind() == InitializedEntity::EK_Base || + Entity.getKind() == InitializedEntity::EK_Member) && + isa<CXXConstructorDecl>(S.CurContext)) { + // This is implicit default initialization of a member or + // base within a constructor. If no viable function was + // found, notify the user that she needs to explicitly + // initialize this base/member. + CXXConstructorDecl *Constructor + = cast<CXXConstructorDecl>(S.CurContext); + if (Entity.getKind() == InitializedEntity::EK_Base) { + S.Diag(Kind.getLocation(), diag::err_missing_default_ctor) + << Constructor->isImplicit() + << S.Context.getTypeDeclType(Constructor->getParent()) + << /*base=*/0 + << Entity.getType(); + + RecordDecl *BaseDecl + = Entity.getBaseSpecifier()->getType()->getAs<RecordType>() + ->getDecl(); + S.Diag(BaseDecl->getLocation(), diag::note_previous_decl) + << S.Context.getTagDeclType(BaseDecl); + } else { + S.Diag(Kind.getLocation(), diag::err_missing_default_ctor) + << Constructor->isImplicit() + << S.Context.getTypeDeclType(Constructor->getParent()) + << /*member=*/1 + << Entity.getName(); + S.Diag(Entity.getDecl()->getLocation(), diag::note_field_decl); + + if (const RecordType *Record + = Entity.getType()->getAs<RecordType>()) + S.Diag(Record->getDecl()->getLocation(), + diag::note_previous_decl) + << S.Context.getTagDeclType(Record->getDecl()); + } + break; + } + S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) << DestType << ArgsRange; S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates, @@ -3597,14 +3746,217 @@ bool InitializationSequence::Diagnose(Sema &S, } case FK_DefaultInitOfConst: - S.Diag(Kind.getLocation(), diag::err_default_init_const) - << DestType; + if (Entity.getKind() == InitializedEntity::EK_Member && + isa<CXXConstructorDecl>(S.CurContext)) { + // This is implicit default-initialization of a const member in + // a constructor. Complain that it needs to be explicitly + // initialized. + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext); + S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor) + << Constructor->isImplicit() + << S.Context.getTypeDeclType(Constructor->getParent()) + << /*const=*/1 + << Entity.getName(); + S.Diag(Entity.getDecl()->getLocation(), diag::note_previous_decl) + << Entity.getName(); + } else { + S.Diag(Kind.getLocation(), diag::err_default_init_const) + << DestType << (bool)DestType->getAs<RecordType>(); + } break; } return true; } +void InitializationSequence::dump(llvm::raw_ostream &OS) const { + switch (SequenceKind) { + case FailedSequence: { + OS << "Failed sequence: "; + switch (Failure) { + case FK_TooManyInitsForReference: + OS << "too many initializers for reference"; + break; + + case FK_ArrayNeedsInitList: + OS << "array requires initializer list"; + break; + + case FK_ArrayNeedsInitListOrStringLiteral: + OS << "array requires initializer list or string literal"; + break; + + case FK_AddressOfOverloadFailed: + OS << "address of overloaded function failed"; + break; + + case FK_ReferenceInitOverloadFailed: + OS << "overload resolution for reference initialization failed"; + break; + + case FK_NonConstLValueReferenceBindingToTemporary: + OS << "non-const lvalue reference bound to temporary"; + break; + + case FK_NonConstLValueReferenceBindingToUnrelated: + OS << "non-const lvalue reference bound to unrelated type"; + break; + + case FK_RValueReferenceBindingToLValue: + OS << "rvalue reference bound to an lvalue"; + break; + + case FK_ReferenceInitDropsQualifiers: + OS << "reference initialization drops qualifiers"; + break; + + case FK_ReferenceInitFailed: + OS << "reference initialization failed"; + break; + + case FK_ConversionFailed: + OS << "conversion failed"; + break; + + case FK_TooManyInitsForScalar: + OS << "too many initializers for scalar"; + break; + + case FK_ReferenceBindingToInitList: + OS << "referencing binding to initializer list"; + break; + + case FK_InitListBadDestinationType: + OS << "initializer list for non-aggregate, non-scalar type"; + break; + + case FK_UserConversionOverloadFailed: + OS << "overloading failed for user-defined conversion"; + break; + + case FK_ConstructorOverloadFailed: + OS << "constructor overloading failed"; + break; + + case FK_DefaultInitOfConst: + OS << "default initialization of a const variable"; + break; + } + OS << '\n'; + return; + } + + case DependentSequence: + OS << "Dependent sequence: "; + return; + + case UserDefinedConversion: + OS << "User-defined conversion sequence: "; + break; + + case ConstructorInitialization: + OS << "Constructor initialization sequence: "; + break; + + case ReferenceBinding: + OS << "Reference binding: "; + break; + + case ListInitialization: + OS << "List initialization: "; + break; + + case ZeroInitialization: + OS << "Zero initialization\n"; + return; + + case NoInitialization: + OS << "No initialization\n"; + return; + + case StandardConversion: + OS << "Standard conversion: "; + break; + + case CAssignment: + OS << "C assignment: "; + break; + + case StringInit: + OS << "String initialization: "; + break; + } + + for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) { + if (S != step_begin()) { + OS << " -> "; + } + + switch (S->Kind) { + case SK_ResolveAddressOfOverloadedFunction: + OS << "resolve address of overloaded function"; + break; + + case SK_CastDerivedToBaseRValue: + OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")"; + break; + + case SK_CastDerivedToBaseLValue: + OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")"; + break; + + case SK_BindReference: + OS << "bind reference to lvalue"; + break; + + case SK_BindReferenceToTemporary: + OS << "bind reference to a temporary"; + break; + + case SK_UserConversion: + OS << "user-defined conversion via " << S->Function->getNameAsString(); + break; + + case SK_QualificationConversionRValue: + OS << "qualification conversion (rvalue)"; + + case SK_QualificationConversionLValue: + OS << "qualification conversion (lvalue)"; + break; + + case SK_ConversionSequence: + OS << "implicit conversion sequence ("; + S->ICS->DebugPrint(); // FIXME: use OS + OS << ")"; + break; + + case SK_ListInitialization: + OS << "list initialization"; + break; + + case SK_ConstructorInitialization: + OS << "constructor initialization"; + break; + + case SK_ZeroInitialization: + OS << "zero initialization"; + break; + + case SK_CAssignment: + OS << "C assignment"; + break; + + case SK_StringInit: + OS << "string initialization"; + break; + } + } +} + +void InitializationSequence::dump() const { + dump(llvm::errs()); +} + //===----------------------------------------------------------------------===// // Initialization helper functions //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index d7d3756020f8..2b49df28fe86 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -15,12 +15,17 @@ #include "SemaOverload.h" #include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" #include "clang/Parse/Action.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include <cassert> +namespace llvm { + class raw_ostream; +} + namespace clang { class CXXBaseSpecifier; @@ -62,7 +67,6 @@ public: /// \brief The entity being initialized is an element of a vector. /// or vector. EK_VectorElement - }; private: @@ -91,8 +95,8 @@ private: /// base class. CXXBaseSpecifier *Base; - /// \brief When Kind = EK_ArrayOrVectorElement, the index of the - /// array or vector element being initialized. + /// \brief When Kind = EK_ArrayElement or EK_VectorElement, the + /// index of the array or vector element being initialized. unsigned Index; }; @@ -197,6 +201,12 @@ public: /// initialized. DeclaratorDecl *getDecl() const; + /// \brief Retrieve the base specifier. + CXXBaseSpecifier *getBaseSpecifier() const { + assert(getKind() == EK_Base && "Not a base specifier"); + return Base; + } + /// \brief Determine the location of the 'return' keyword when initializing /// the result of a function call. SourceLocation getReturnLoc() const { @@ -440,7 +450,11 @@ public: /// \brief When Kind == SK_ResolvedOverloadedFunction or Kind == /// SK_UserConversion, the function that the expression should be /// resolved to or the conversion function to call, respectively. - FunctionDecl *Function; + /// + /// Always a FunctionDecl. + /// For conversion decls, the naming class is the source type. + /// For construct decls, the naming class is the target type. + DeclAccessPair Function; /// \brief When Kind = SK_ConversionSequence, the implicit conversion /// sequence @@ -607,7 +621,9 @@ public: /// \brief Add a new step invoking a conversion function, which is either /// a constructor or a conversion function. - void AddUserConversionStep(FunctionDecl *Function, QualType T); + void AddUserConversionStep(FunctionDecl *Function, + AccessSpecifier Access, + QualType T); /// \brief Add a new step that performs a qualification conversion to the /// given type. @@ -622,6 +638,7 @@ public: /// \brief Add a constructor-initialization step. void AddConstructorInitializationStep(CXXConstructorDecl *Constructor, + AccessSpecifier Access, QualType T); /// \brief Add a zero-initialization step. @@ -658,6 +675,14 @@ public: assert(getKind() == FailedSequence && "Not an initialization failure!"); return Failure; } + + /// \brief Dump a representation of this initialization sequence to + /// the given stream, for debugging purposes. + void dump(llvm::raw_ostream &OS) const; + + /// \brief Dump a representation of this initialization sequence to + /// standard error, for debugging purposes. + void dump() const; }; } // end namespace clang diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index f5d2a7d89988..c7569d6eda25 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -404,7 +404,7 @@ void LookupResult::resolveKind() { } void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { - CXXBasePaths::paths_iterator I, E; + CXXBasePaths::const_paths_iterator I, E; DeclContext::lookup_iterator DI, DE; for (I = P.begin(), E = P.end(); I != E; ++I) for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI) @@ -438,9 +438,42 @@ void LookupResult::print(llvm::raw_ostream &Out) { } } +/// \brief Lookup a builtin function, when name lookup would otherwise +/// fail. +static bool LookupBuiltin(Sema &S, LookupResult &R) { + Sema::LookupNameKind NameKind = R.getLookupKind(); + + // If we didn't find a use of this identifier, and if the identifier + // corresponds to a compiler builtin, create the decl object for the builtin + // now, injecting it into translation unit scope, and return it. + if (NameKind == Sema::LookupOrdinaryName || + NameKind == Sema::LookupRedeclarationWithLinkage) { + IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo(); + if (II) { + // If this is a builtin on this (or all) targets, create the decl. + if (unsigned BuiltinID = II->getBuiltinID()) { + // In C++, we don't have any predefined library functions like + // 'malloc'. Instead, we'll just error. + if (S.getLangOptions().CPlusPlus && + S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + return false; + + NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, + S.TUScope, R.isForRedeclaration(), + R.getNameLoc()); + if (D) + R.addDecl(D); + return (D != NULL); + } + } + } + + return false; +} + // Adds all qualifying matches for a name within a decl context to the // given lookup result. Returns true if any matches were found. -static bool LookupDirect(LookupResult &R, const DeclContext *DC) { +static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { bool Found = false; DeclContext::lookup_const_iterator I, E; @@ -452,87 +485,89 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { } } + if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R)) + return true; + if (R.getLookupName().getNameKind() - == DeclarationName::CXXConversionFunctionName && - !R.getLookupName().getCXXNameType()->isDependentType() && - isa<CXXRecordDecl>(DC)) { + != DeclarationName::CXXConversionFunctionName || + R.getLookupName().getCXXNameType()->isDependentType() || + !isa<CXXRecordDecl>(DC)) + return Found; + + // C++ [temp.mem]p6: + // A specialization of a conversion function template is not found by + // name lookup. Instead, any conversion function templates visible in the + // context of the use are considered. [...] + const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); + if (!Record->isDefinition()) + return Found; + + const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); + for (UnresolvedSetImpl::iterator U = Unresolved->begin(), + UEnd = Unresolved->end(); U != UEnd; ++U) { + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U); + if (!ConvTemplate) + continue; + + // When we're performing lookup for the purposes of redeclaration, just + // add the conversion function template. When we deduce template + // arguments for specializations, we'll end up unifying the return + // type of the new declaration with the type of the function template. + if (R.isForRedeclaration()) { + R.addDecl(ConvTemplate); + Found = true; + continue; + } + // C++ [temp.mem]p6: - // A specialization of a conversion function template is not found by - // name lookup. Instead, any conversion function templates visible in the - // context of the use are considered. [...] - const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); - if (!Record->isDefinition()) - return Found; - - const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); - for (UnresolvedSetImpl::iterator U = Unresolved->begin(), - UEnd = Unresolved->end(); U != UEnd; ++U) { - FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U); - if (!ConvTemplate) - continue; - - // When we're performing lookup for the purposes of redeclaration, just - // add the conversion function template. When we deduce template - // arguments for specializations, we'll end up unifying the return - // type of the new declaration with the type of the function template. - if (R.isForRedeclaration()) { - R.addDecl(ConvTemplate); - Found = true; - continue; - } - - // C++ [temp.mem]p6: - // [...] For each such operator, if argument deduction succeeds - // (14.9.2.3), the resulting specialization is used as if found by - // name lookup. - // - // When referencing a conversion function for any purpose other than - // a redeclaration (such that we'll be building an expression with the - // result), perform template argument deduction and place the - // specialization into the result set. We do this to avoid forcing all - // callers to perform special deduction for conversion functions. - Sema::TemplateDeductionInfo Info(R.getSema().Context); - FunctionDecl *Specialization = 0; - - const FunctionProtoType *ConvProto - = ConvTemplate->getTemplatedDecl()->getType() - ->getAs<FunctionProtoType>(); - assert(ConvProto && "Nonsensical conversion function template type"); - - // 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! - QualType ExpectedType - = R.getSema().Context.getFunctionType( - R.getLookupName().getCXXNameType(), - 0, 0, ConvProto->isVariadic(), - ConvProto->getTypeQuals(), - false, false, 0, 0, - ConvProto->getNoReturnAttr()); - - // Perform template argument deduction against the type that we would - // expect the function to have. - if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType, - Specialization, Info) - == Sema::TDK_Success) { - R.addDecl(Specialization); - Found = true; - } + // [...] For each such operator, if argument deduction succeeds + // (14.9.2.3), the resulting specialization is used as if found by + // name lookup. + // + // When referencing a conversion function for any purpose other than + // a redeclaration (such that we'll be building an expression with the + // result), perform template argument deduction and place the + // specialization into the result set. We do this to avoid forcing all + // callers to perform special deduction for conversion functions. + Sema::TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc()); + FunctionDecl *Specialization = 0; + + const FunctionProtoType *ConvProto + = ConvTemplate->getTemplatedDecl()->getType()->getAs<FunctionProtoType>(); + assert(ConvProto && "Nonsensical conversion function template type"); + + // 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! + QualType ExpectedType + = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), + 0, 0, ConvProto->isVariadic(), + ConvProto->getTypeQuals(), + false, false, 0, 0, + ConvProto->getNoReturnAttr()); + + // Perform template argument deduction against the type that we would + // expect the function to have. + if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType, + Specialization, Info) + == Sema::TDK_Success) { + R.addDecl(Specialization); + Found = true; } } - + return Found; } // Performs C++ unqualified lookup into the given file context. static bool -CppNamespaceLookup(LookupResult &R, ASTContext &Context, DeclContext *NS, - UnqualUsingDirectiveSet &UDirs) { +CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, + DeclContext *NS, UnqualUsingDirectiveSet &UDirs) { assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); // Perform direct name lookup into the LookupCtx. - bool Found = LookupDirect(R, NS); + bool Found = LookupDirect(S, R, NS); // Perform direct name lookup into the namespaces nominated by the // using directives whose common ancestor is this namespace. @@ -540,7 +575,7 @@ CppNamespaceLookup(LookupResult &R, ASTContext &Context, DeclContext *NS, llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(NS); for (; UI != UEnd; ++UI) - if (LookupDirect(R, UI->getNominatedNamespace())) + if (LookupDirect(S, R, UI->getNominatedNamespace())) Found = true; R.resolveKind(); @@ -650,12 +685,9 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { for (; S; S = S->getParent()) { DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity()); - if (!Ctx || Ctx->isTransparentContext()) + if (Ctx && Ctx->isTransparentContext()) continue; - assert(Ctx && Ctx->isFileContext() && - "We should have been looking only at file context here already."); - // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { @@ -669,16 +701,21 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { } } - // Look into context considering using-directives. - if (CppNamespaceLookup(R, Context, Ctx, UDirs)) - Found = true; + if (Ctx) { + assert(Ctx->isFileContext() && + "We should have been looking only at file context here already."); + + // Look into context considering using-directives. + if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) + Found = true; + } if (Found) { R.resolveKind(); return true; } - if (R.isForRedeclaration() && !Ctx->isTransparentContext()) + if (R.isForRedeclaration() && Ctx && !Ctx->isTransparentContext()) return false; } @@ -793,26 +830,9 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin // now, injecting it into translation unit scope, and return it. - if (NameKind == LookupOrdinaryName || - NameKind == LookupRedeclarationWithLinkage) { - IdentifierInfo *II = Name.getAsIdentifierInfo(); - if (II && AllowBuiltinCreation) { - // If this is a builtin on this (or all) targets, create the decl. - if (unsigned BuiltinID = II->getBuiltinID()) { - // In C++, we don't have any predefined library functions like - // 'malloc'. Instead, we'll just error. - if (getLangOptions().CPlusPlus && - Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) - return false; + if (AllowBuiltinCreation) + return LookupBuiltin(*this, R); - NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, - S, R.isForRedeclaration(), - R.getNameLoc()); - if (D) R.addDecl(D); - return (D != NULL); - } - } - } return false; } @@ -842,7 +862,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { /// class or enumeration name if and only if the declarations are /// from the same namespace; otherwise (the declarations are from /// different namespaces), the program is ill-formed. -static bool LookupQualifiedNameInUsingDirectives(LookupResult &R, +static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, DeclContext *StartDC) { assert(StartDC->isFileContext() && "start context is not a file context"); @@ -885,7 +905,7 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R, // between LookupResults. bool UseLocal = !R.empty(); LookupResult &DirectR = UseLocal ? LocalR : R; - bool FoundDirect = LookupDirect(DirectR, ND); + bool FoundDirect = LookupDirect(S, DirectR, ND); if (FoundDirect) { // First do any local hiding. @@ -965,7 +985,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, "Declaration context must already be complete!"); // Perform qualified name lookup into the LookupCtx. - if (LookupDirect(R, LookupCtx)) { + if (LookupDirect(*this, R, LookupCtx)) { R.resolveKind(); if (isa<CXXRecordDecl>(LookupCtx)) R.setNamingClass(cast<CXXRecordDecl>(LookupCtx)); @@ -986,7 +1006,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // If this is a namespace, look it up in the implied namespaces. if (LookupCtx->isFileContext()) - return LookupQualifiedNameInUsingDirectives(R, LookupCtx); + return LookupQualifiedNameInUsingDirectives(*this, R, LookupCtx); // If this isn't a C++ class, we aren't allowed to look into base // classes, we're done. @@ -1407,6 +1427,12 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, AssociatedClasses); } + // Only recurse into base classes for complete types. + if (!Class->hasDefinition()) { + // FIXME: we might need to instantiate templates here + return; + } + // Add direct and indirect base classes along with their associated // namespaces. llvm::SmallVector<CXXRecordDecl *, 32> Bases; @@ -1693,7 +1719,7 @@ ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) { void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, - FunctionSet &Functions) { + UnresolvedSetImpl &Functions) { // C++ [over.match.oper]p3: // -- The set of non-member candidates is the result of the // unqualified lookup of operator@ in the context of the @@ -1719,29 +1745,58 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, Op != OpEnd; ++Op) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) { if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) - Functions.insert(FD); // FIXME: canonical FD + Functions.addDecl(FD, Op.getAccess()); // FIXME: canonical FD } else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*Op)) { // FIXME: friend operators? // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate, // later? if (!FunTmpl->getDeclContext()->isRecord()) - Functions.insert(FunTmpl); + Functions.addDecl(FunTmpl, Op.getAccess()); } } } -static void CollectFunctionDecl(Sema::FunctionSet &Functions, - Decl *D) { - if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) - Functions.insert(Func); - else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) - Functions.insert(FunTmpl); +void ADLResult::insert(NamedDecl *New) { + NamedDecl *&Old = Decls[cast<NamedDecl>(New->getCanonicalDecl())]; + + // If we haven't yet seen a decl for this key, or the last decl + // was exactly this one, we're done. + if (Old == 0 || Old == New) { + Old = New; + return; + } + + // Otherwise, decide which is a more recent redeclaration. + FunctionDecl *OldFD, *NewFD; + if (isa<FunctionTemplateDecl>(New)) { + OldFD = cast<FunctionTemplateDecl>(Old)->getTemplatedDecl(); + NewFD = cast<FunctionTemplateDecl>(New)->getTemplatedDecl(); + } else { + OldFD = cast<FunctionDecl>(Old); + NewFD = cast<FunctionDecl>(New); + } + + FunctionDecl *Cursor = NewFD; + while (true) { + Cursor = Cursor->getPreviousDeclaration(); + + // If we got to the end without finding OldFD, OldFD is the newer + // declaration; leave things as they are. + if (!Cursor) return; + + // If we do find OldFD, then NewFD is newer. + if (Cursor == OldFD) break; + + // Otherwise, keep looking. + } + + Old = New; } void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, - FunctionSet &Functions) { + ADLResult &Result) { // Find all of the associated namespaces and classes based on the // arguments we have. AssociatedNamespaceSet AssociatedNamespaces; @@ -1784,7 +1839,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, // lookup (11.4). DeclContext::lookup_iterator I, E; for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) { - Decl *D = *I; + NamedDecl *D = *I; // If the only declaration here is an ordinary friend, consider // it only if it was declared in an associated classes. if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) { @@ -1793,10 +1848,18 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, continue; } - FunctionDecl *Fn; - if (!Operator || !(Fn = dyn_cast<FunctionDecl>(D)) || - IsAcceptableNonMemberOperatorCandidate(Fn, T1, T2, Context)) - CollectFunctionDecl(Functions, D); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + if (isa<FunctionDecl>(D)) { + if (Operator && + !IsAcceptableNonMemberOperatorCandidate(cast<FunctionDecl>(D), + T1, T2, Context)) + continue; + } else if (!isa<FunctionTemplateDecl>(D)) + continue; + + Result.insert(D); } } } @@ -1985,6 +2048,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, bool InBaseClass, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited) { + if (!Ctx) + return; + // Make sure we don't visit the same context twice. if (Visited.visitedContext(Ctx->getPrimaryContext())) return; @@ -2022,6 +2088,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Traverse the contexts of inherited C++ classes. if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { + if (!Record->hasDefinition()) + return; + for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), BEnd = Record->bases_end(); B != BEnd; ++B) { @@ -2138,9 +2207,9 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // For instance methods, look for ivars in the method's interface. LookupResult IvarResult(Result.getSema(), Result.getLookupName(), Result.getNameLoc(), Sema::LookupMemberName); - ObjCInterfaceDecl *IFace = Method->getClassInterface(); - LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); + if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) + LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false, Consumer, Visited); } // We've already performed all of the name lookup that we need @@ -2312,9 +2381,16 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT) { - if (Diags.hasFatalErrorOccurred()) return false; + + // Provide a stop gap for files that are just seriously broken. Trying + // to correct all typos can turn into a HUGE performance penalty, causing + // some files to take minutes to get rejected by the parser. + // FIXME: Is this the right solution? + if (TyposCorrected == 20) + return false; + ++TyposCorrected; // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 44a8f15e57b6..b79b1cc99375 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -148,7 +148,7 @@ bool StandardConversionSequence::isPointerConversionToBool() const { // array-to-pointer or function-to-pointer implicit conversions, so // check for their presence as well as checking whether FromType is // a pointer. - if (getToType()->isBooleanType() && + if (getToType(1)->isBooleanType() && (getFromType()->isPointerType() || getFromType()->isBlockPointerType() || First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer)) return true; @@ -164,7 +164,7 @@ bool StandardConversionSequence:: isPointerConversionToVoidPointer(ASTContext& Context) const { QualType FromType = getFromType(); - QualType ToType = getToType(); + QualType ToType = getToType(1); // Note that FromType has not necessarily been transformed by the // array-to-pointer implicit conversion, so check for its presence @@ -447,16 +447,24 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, bool InOverloadResolution, bool UserCast) { ImplicitConversionSequence ICS; - OverloadCandidateSet Conversions; - OverloadingResult UserDefResult = OR_Success; - if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) + if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) { ICS.setStandard(); - else if (getLangOptions().CPlusPlus && - (UserDefResult = IsUserDefinedConversion(From, ToType, - ICS.UserDefined, - Conversions, - !SuppressUserConversions, AllowExplicit, - ForceRValue, UserCast)) == OR_Success) { + return ICS; + } + + if (!getLangOptions().CPlusPlus) { + ICS.setBad(); + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); + return ICS; + } + + OverloadCandidateSet Conversions(From->getExprLoc()); + OverloadingResult UserDefResult + = IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions, + !SuppressUserConversions, AllowExplicit, + ForceRValue, UserCast); + + if (UserDefResult == OR_Success) { ICS.setUserDefined(); // C++ [over.ics.user]p4: // A conversion of an expression of class type to the same class @@ -477,7 +485,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); ICS.Standard.setFromType(From->getType()); - ICS.Standard.setToType(ToType); + ICS.Standard.setAllToTypes(ToType); ICS.Standard.CopyConstructor = Constructor; if (ToCanon != FromCanon) ICS.Standard.Second = ICK_Derived_To_Base; @@ -595,7 +603,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // conversion (4.4). (C++ 4.2p2) SCS.Second = ICK_Identity; SCS.Third = ICK_Qualification; - SCS.setToType(ToType); + SCS.setAllToTypes(FromType); return true; } } else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) { @@ -634,6 +642,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // We don't require any conversions for the first step. SCS.First = ICK_Identity; } + SCS.setToType(0, FromType); // The second conversion can be an integral promotion, floating // point promotion, integral conversion, floating point conversion, @@ -714,6 +723,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // No second conversion required. SCS.Second = ICK_Identity; } + SCS.setToType(1, FromType); QualType CanonFrom; QualType CanonTo; @@ -740,13 +750,13 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, CanonFrom = CanonTo; } } + SCS.setToType(2, FromType); // If we have not converted the argument type to the parameter type, // this is a bad conversion sequence. if (CanonFrom != CanonTo) return false; - SCS.setToType(FromType); return true; } @@ -766,7 +776,8 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // int can represent all the values of the source type; otherwise, // the source rvalue can be converted to an rvalue of type unsigned // int (C++ 4.5p1). - if (FromType->isPromotableIntegerType() && !FromType->isBooleanType()) { + if (FromType->isPromotableIntegerType() && !FromType->isBooleanType() && + !FromType->isEnumeralType()) { if (// We can promote any signed, promotable integer type to an int (FromType->isSignedIntegerType() || // We can promote any unsigned integer type whose size is @@ -1344,14 +1355,13 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, /// CheckMemberPointerConversion - Check the member pointer conversion from the /// expression From to the type ToType. This routine checks for ambiguous or -/// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions +/// virtual or inaccessible base-to-derived member pointer conversions /// for which IsMemberPointerConversion has already returned true. It returns /// true and produces a diagnostic if there was an error, or returns false /// otherwise. bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, CastExpr::CastKind &Kind, bool IgnoreBaseAccess) { - (void)IgnoreBaseAccess; QualType FromType = From->getType(); const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>(); if (!FromPtrType) { @@ -1374,7 +1384,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, assert(FromClass->isRecordType() && "Pointer into non-class."); assert(ToClass->isRecordType() && "Pointer into non-class."); - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/ true, /*DetectVirtual=*/true); bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths); assert(DerivationOkay && @@ -1383,13 +1393,6 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, if (Paths.isAmbiguous(Context.getCanonicalType(FromClass). getUnqualifiedType())) { - // Derivation is ambiguous. Redo the check to find the exact paths. - Paths.clear(); - Paths.setRecordingPaths(true); - bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths); - assert(StillOkay && "Derivation changed due to quantum fluctuation."); - (void)StillOkay; - std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths); Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv) << 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange(); @@ -1403,6 +1406,10 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, return true; } + if (!IgnoreBaseAccess) + CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true, + FromClass, ToClass, Paths.front()); + // Must be a base to derived member conversion. Kind = CastExpr::CK_BaseToDerivedMemberPointer; return false; @@ -1418,7 +1425,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { // If FromType and ToType are the same type, this is not a // qualification conversion. - if (FromType == ToType) + if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType()) return false; // (C++ 4.4p4): @@ -1526,13 +1533,16 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + AddTemplateOverloadCandidate(ConstructorTmpl, + ConstructorTmpl->getAccess(), + /*ExplicitArgs*/ 0, &From, 1, CandidateSet, SuppressUserConversions, ForceRValue); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). - AddOverloadCandidate(Constructor, &From, 1, CandidateSet, + AddOverloadCandidate(Constructor, Constructor->getAccess(), + &From, 1, CandidateSet, SuppressUserConversions, ForceRValue); } } @@ -1568,11 +1578,12 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, ActingContext, - From, ToType, CandidateSet); + AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), + ActingContext, From, ToType, + CandidateSet); else - AddConversionCandidate(Conv, ActingContext, From, ToType, - CandidateSet); + AddConversionCandidate(Conv, I.getAccess(), ActingContext, + From, ToType, CandidateSet); } } } @@ -1601,7 +1612,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, User.After.setAsIdentityConversion(); User.After.setFromType( ThisType->getAs<PointerType>()->getPointeeType()); - User.After.setToType(ToType); + User.After.setAllToTypes(ToType); return OR_Success; } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(Best->Function)) { @@ -1647,7 +1658,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, bool Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { ImplicitConversionSequence ICS; - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(From->getExprLoc()); OverloadingResult OvResult = IsUserDefinedConversion(From, ToType, ICS.UserDefined, CandidateSet, true, false, false); @@ -1718,6 +1729,43 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, return ImplicitConversionSequence::Indistinguishable; } +// Per 13.3.3.2p3, compare the given standard conversion sequences to +// determine if one is a proper subset of the other. +static ImplicitConversionSequence::CompareKind +compareStandardConversionSubsets(ASTContext &Context, + const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2) { + ImplicitConversionSequence::CompareKind Result + = ImplicitConversionSequence::Indistinguishable; + + if (SCS1.Second != SCS2.Second) { + if (SCS1.Second == ICK_Identity) + Result = ImplicitConversionSequence::Better; + else if (SCS2.Second == ICK_Identity) + Result = ImplicitConversionSequence::Worse; + else + return ImplicitConversionSequence::Indistinguishable; + } else if (!Context.hasSameType(SCS1.getToType(1), SCS2.getToType(1))) + return ImplicitConversionSequence::Indistinguishable; + + if (SCS1.Third == SCS2.Third) { + return Context.hasSameType(SCS1.getToType(2), SCS2.getToType(2))? Result + : ImplicitConversionSequence::Indistinguishable; + } + + if (SCS1.Third == ICK_Identity) + return Result == ImplicitConversionSequence::Worse + ? ImplicitConversionSequence::Indistinguishable + : ImplicitConversionSequence::Better; + + if (SCS2.Third == ICK_Identity) + return Result == ImplicitConversionSequence::Better + ? ImplicitConversionSequence::Indistinguishable + : ImplicitConversionSequence::Worse; + + return ImplicitConversionSequence::Indistinguishable; +} + /// CompareStandardConversionSequences - Compare two standard /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2p3). @@ -1733,21 +1781,9 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // excluding any Lvalue Transformation; the identity conversion // sequence is considered to be a subsequence of any // non-identity conversion sequence) or, if not that, - if (SCS1.Second == SCS2.Second && SCS1.Third == SCS2.Third) - // Neither is a proper subsequence of the other. Do nothing. - ; - else if ((SCS1.Second == ICK_Identity && SCS1.Third == SCS2.Third) || - (SCS1.Third == ICK_Identity && SCS1.Second == SCS2.Second) || - (SCS1.Second == ICK_Identity && - SCS1.Third == ICK_Identity)) - // SCS1 is a proper subsequence of SCS2. - return ImplicitConversionSequence::Better; - else if ((SCS2.Second == ICK_Identity && SCS2.Third == SCS1.Third) || - (SCS2.Third == ICK_Identity && SCS2.Second == SCS1.Second) || - (SCS2.Second == ICK_Identity && - SCS2.Third == ICK_Identity)) - // SCS2 is a proper subsequence of SCS1. - return ImplicitConversionSequence::Worse; + if (ImplicitConversionSequence::CompareKind CK + = compareStandardConversionSubsets(Context, SCS1, SCS2)) + return CK; // -- the rank of S1 is better than the rank of S2 (by the rules // defined below), or, if not that, @@ -1852,8 +1888,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // top-level cv-qualifiers, and the type to which the reference // initialized by S2 refers is more cv-qualified than the type // to which the reference initialized by S1 refers. - QualType T1 = SCS1.getToType(); - QualType T2 = SCS2.getToType(); + QualType T1 = SCS1.getToType(2); + QualType T2 = SCS2.getToType(2); T1 = Context.getCanonicalType(T1); T2 = Context.getCanonicalType(T2); Qualifiers T1Quals, T2Quals; @@ -1894,8 +1930,8 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, // FIXME: the example in the standard doesn't use a qualification // conversion (!) - QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); - QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + QualType T1 = SCS1.getToType(2); + QualType T2 = SCS2.getToType(2); T1 = Context.getCanonicalType(T1); T2 = Context.getCanonicalType(T2); Qualifiers T1Quals, T2Quals; @@ -1984,9 +2020,9 @@ ImplicitConversionSequence::CompareKind Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2) { QualType FromType1 = SCS1.getFromType(); - QualType ToType1 = SCS1.getToType(); + QualType ToType1 = SCS1.getToType(1); QualType FromType2 = SCS2.getFromType(); - QualType ToType2 = SCS2.getToType(); + QualType ToType2 = SCS2.getToType(1); // Adjust the types we're converting from via the array-to-pointer // conversion, if we need to. @@ -2276,7 +2312,7 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType, // Success. Mark this as a reference binding. ICS.setStandard(); ICS.Standard.setFromType(FromType); - ICS.Standard.setToType(ImplicitParamType); + ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; ICS.Standard.RRefBinding = false; @@ -2360,6 +2396,7 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { /// code completion. void Sema::AddOverloadCandidate(FunctionDecl *Function, + AccessSpecifier Access, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, @@ -2380,7 +2417,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // function, e.g., X::f(). We use an empty type for the implied // object argument (C++ [over.call.func]p3), and the acting context // is irrelevant. - AddMethodCandidate(Method, Method->getParent(), + AddMethodCandidate(Method, Access, Method->getParent(), QualType(), Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); return; @@ -2410,6 +2447,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); Candidate.Function = Function; + Candidate.Access = Access; Candidate.Viable = true; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; @@ -2469,35 +2507,33 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, /// \brief Add all of the function declarations in the given function set to /// the overload canddiate set. -void Sema::AddFunctionCandidates(const FunctionSet &Functions, +void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { - for (FunctionSet::const_iterator F = Functions.begin(), - FEnd = Functions.end(); - F != FEnd; ++F) { + for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { // FIXME: using declarations if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) { if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) - AddMethodCandidate(cast<CXXMethodDecl>(FD), + AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getAccess(), cast<CXXMethodDecl>(FD)->getParent(), Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else - AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, + AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet, SuppressUserConversions); } else { FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*F); if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) && !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic()) - AddMethodTemplateCandidate(FunTmpl, + AddMethodTemplateCandidate(FunTmpl, F.getAccess(), cast<CXXRecordDecl>(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else - AddTemplateOverloadCandidate(FunTmpl, + AddTemplateOverloadCandidate(FunTmpl, AS_none, /*FIXME: explicit args */ 0, Args, NumArgs, CandidateSet, SuppressUserConversions); @@ -2508,6 +2544,7 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, /// AddMethodCandidate - Adds a named decl (which is some kind of /// method) as a method candidate to the given overload set. void Sema::AddMethodCandidate(NamedDecl *Decl, + AccessSpecifier Access, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2520,13 +2557,13 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) { assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) && "Expected a member function template"); - AddMethodTemplateCandidate(TD, ActingContext, /*ExplicitArgs*/ 0, + AddMethodTemplateCandidate(TD, Access, ActingContext, /*ExplicitArgs*/ 0, ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } else { - AddMethodCandidate(cast<CXXMethodDecl>(Decl), ActingContext, + AddMethodCandidate(cast<CXXMethodDecl>(Decl), Access, ActingContext, ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2542,8 +2579,9 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, /// a slightly hacky way to implement the overloading rules for elidable copy /// initialization in C++0x (C++0x 12.8p15). void -Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, - QualType ObjectType, Expr **Args, unsigned NumArgs, +Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { const FunctionProtoType* Proto @@ -2562,6 +2600,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); Candidate.Function = Method; + Candidate.Access = Access; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; @@ -2639,6 +2678,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, /// function template specialization. void Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + AccessSpecifier Access, CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, @@ -2658,7 +2698,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, // functions. In such a case, the candidate functions generated from each // function template are combined with the set of non-template candidate // functions. - TemplateDeductionInfo Info(Context); + TemplateDeductionInfo Info(Context, CandidateSet.getLocation()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult Result = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, @@ -2674,8 +2714,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, assert(Specialization && "Missing member function template specialization?"); assert(isa<CXXMethodDecl>(Specialization) && "Specialization is not a member function?"); - AddMethodCandidate(cast<CXXMethodDecl>(Specialization), ActingContext, - ObjectType, Args, NumArgs, + AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Access, + ActingContext, ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2684,6 +2724,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, /// an appropriate function template specialization. void Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, + AccessSpecifier Access, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2701,29 +2742,30 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, // functions. In such a case, the candidate functions generated from each // function template are combined with the set of non-template candidate // functions. - TemplateDeductionInfo Info(Context); + TemplateDeductionInfo Info(Context, CandidateSet.getLocation()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args, NumArgs, Specialization, Info)) { - // FIXME: Record what happened with template argument deduction, so - // that we can give the user a beautiful diagnostic. - (void) Result; - CandidateSet.push_back(OverloadCandidate()); OverloadCandidate &Candidate = CandidateSet.back(); Candidate.Function = FunctionTemplate->getTemplatedDecl(); + Candidate.Access = Access; Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; + + // TODO: record more information about failed template arguments + Candidate.DeductionFailure.Result = Result; + Candidate.DeductionFailure.TemplateParameter = Info.Param.getOpaqueValue(); return; } // Add the function template specialization produced by template argument // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddOverloadCandidate(Specialization, Args, NumArgs, CandidateSet, + AddOverloadCandidate(Specialization, Access, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2735,6 +2777,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, /// conversion function produces). void Sema::AddConversionCandidate(CXXConversionDecl *Conversion, + AccessSpecifier Access, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet) { @@ -2751,11 +2794,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); Candidate.Function = Conversion; + Candidate.Access = Access; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); Candidate.FinalConversion.setFromType(Conversion->getConversionType()); - Candidate.FinalConversion.setToType(ToType); + Candidate.FinalConversion.setAllToTypes(ToType); // Determine the implicit conversion sequence for the implicit // object parameter. @@ -2837,6 +2881,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, /// [temp.deduct.conv]). void Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + AccessSpecifier Access, CXXRecordDecl *ActingDC, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet) { @@ -2846,7 +2891,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, if (!CandidateSet.isNewCandidate(FunctionTemplate)) return; - TemplateDeductionInfo Info(Context); + TemplateDeductionInfo Info(Context, CandidateSet.getLocation()); CXXConversionDecl *Specialization = 0; if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, ToType, @@ -2860,7 +2905,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, // Add the conversion function template specialization produced by // template argument deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddConversionCandidate(Specialization, ActingDC, From, ToType, CandidateSet); + AddConversionCandidate(Specialization, Access, ActingDC, From, ToType, + CandidateSet); } /// AddSurrogateCandidate - Adds a "surrogate" candidate function that @@ -2869,6 +2915,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, /// with the given arguments (C++ [over.call.object]p2-4). Proto is /// the type of function that we'll eventually be calling. void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, + AccessSpecifier Access, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, QualType ObjectType, @@ -2883,6 +2930,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); Candidate.Function = 0; + Candidate.Access = Access; Candidate.Surrogate = Conversion; Candidate.Viable = true; Candidate.IsSurrogate = true; @@ -2968,7 +3016,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, SourceRange OpRange) { - FunctionSet Functions; + UnresolvedSet<16> Fns; QualType T1 = Args[0]->getType(); QualType T2; @@ -2977,9 +3025,10 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); if (S) - LookupOverloadedOperatorName(Op, S, T1, T2, Functions); - ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, Functions); - AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet); + LookupOverloadedOperatorName(Op, S, T1, T2, Fns); + AddFunctionCandidates(Fns, Args, NumArgs, CandidateSet, false); + AddArgumentDependentLookupCandidates(OpName, false, Args, NumArgs, 0, + CandidateSet); AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange); AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet); } @@ -3029,7 +3078,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, OperEnd = Operators.end(); Oper != OperEnd; ++Oper) - AddMethodCandidate(*Oper, Args[0]->getType(), + AddMethodCandidate(*Oper, Oper.getAccess(), Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, /* SuppressUserConversions = */ false); } @@ -3055,6 +3104,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); Candidate.Function = 0; + Candidate.Access = AS_none; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.BuiltinTypes.ResultTy = ResultTy; @@ -3362,6 +3412,9 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { } CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); + if (!ClassDecl->hasDefinition()) + return VRQuals; + const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions(); @@ -4108,54 +4161,45 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, /// candidate set (C++ [basic.lookup.argdep]). void Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, + bool Operator, Expr **Args, unsigned NumArgs, const TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading) { - FunctionSet Functions; + ADLResult Fns; - // FIXME: Should we be trafficking in canonical function decls throughout? - - // Record all of the function candidates that we've already - // added to the overload set, so that we don't add those same - // candidates a second time. - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), - CandEnd = CandidateSet.end(); - Cand != CandEnd; ++Cand) - if (Cand->Function) { - Functions.insert(Cand->Function); - if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate()) - Functions.insert(FunTmpl); - } + // FIXME: This approach for uniquing ADL results (and removing + // redundant candidates from the set) relies on pointer-equality, + // which means we need to key off the canonical decl. However, + // always going back to the canonical decl might not get us the + // right set of default arguments. What default arguments are + // we supposed to consider on ADL candidates, anyway? // FIXME: Pass in the explicit template arguments? - ArgumentDependentLookup(Name, /*Operator*/false, Args, NumArgs, Functions); + ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns); // Erase all of the candidates we already knew about. - // FIXME: This is suboptimal. Is there a better way? for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), CandEnd = CandidateSet.end(); Cand != CandEnd; ++Cand) if (Cand->Function) { - Functions.erase(Cand->Function); + Fns.erase(Cand->Function); if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate()) - Functions.erase(FunTmpl); + Fns.erase(FunTmpl); } // For each of the ADL candidates we found, add it to the overload // set. - for (FunctionSet::iterator Func = Functions.begin(), - FuncEnd = Functions.end(); - Func != FuncEnd; ++Func) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) { + for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { if (ExplicitTemplateArgs) continue; - AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, + AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet, false, false, PartialOverloading); } else - AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func), - ExplicitTemplateArgs, + AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), + AS_none, ExplicitTemplateArgs, Args, NumArgs, CandidateSet); } } @@ -4164,7 +4208,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, /// candidate is a better candidate than the second (C++ 13.3.3p1). bool Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, - const OverloadCandidate& Cand2) { + const OverloadCandidate& Cand2, + SourceLocation Loc) { // Define viable functions to be better candidates than non-viable // functions. if (!Cand2.Viable) @@ -4227,6 +4272,7 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, if (FunctionTemplateDecl *BetterTemplate = getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(), Cand2.Function->getPrimaryTemplate(), + Loc, isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion : TPOC_Call)) return BetterTemplate == Cand1.Function->getPrimaryTemplate(); @@ -4279,7 +4325,8 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); Cand != CandidateSet.end(); ++Cand) { if (Cand->Viable) { - if (Best == CandidateSet.end() || isBetterOverloadCandidate(*Cand, *Best)) + if (Best == CandidateSet.end() || + isBetterOverloadCandidate(*Cand, *Best, Loc)) Best = Cand; } } @@ -4294,7 +4341,7 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, Cand != CandidateSet.end(); ++Cand) { if (Cand->Viable && Cand != Best && - !isBetterOverloadCandidate(*Best, *Cand)) { + !isBetterOverloadCandidate(*Best, *Cand, Loc)) { Best = CandidateSet.end(); return OR_Ambiguous; } @@ -4414,6 +4461,20 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { QualType FromTy = Conv.Bad.getFromType(); QualType ToTy = Conv.Bad.getToType(); + if (FromTy == S.Context.OverloadTy) { + assert(FromExpr); + Expr *E = FromExpr->IgnoreParens(); + if (isa<UnaryOperator>(E)) + E = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); + DeclarationName Name = cast<OverloadExpr>(E)->getName(); + + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_overload) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << ToTy << Name << I+1; + return; + } + // Do some hand-waving analysis to see if the non-viability is due // to a qualifier mismatch. CanQualType CFromTy = S.Context.getCanonicalType(FromTy); @@ -4520,6 +4581,58 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs; } +/// Diagnose a failed template-argument deduction. +void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, + Expr **Args, unsigned NumArgs) { + FunctionDecl *Fn = Cand->Function; // pattern + + TemplateParameter Param = TemplateParameter::getFromOpaqueValue( + Cand->DeductionFailure.TemplateParameter); + + switch (Cand->DeductionFailure.Result) { + case Sema::TDK_Success: + llvm_unreachable("TDK_success while diagnosing bad deduction"); + + case Sema::TDK_Incomplete: { + NamedDecl *ParamD; + (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) || + (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) || + (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>()); + assert(ParamD && "no parameter found for incomplete deduction result"); + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction) + << ParamD->getDeclName(); + return; + } + + // TODO: diagnose these individually, then kill off + // note_ovl_candidate_bad_deduction, which is uselessly vague. + case Sema::TDK_InstantiationDepth: + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + case Sema::TDK_SubstitutionFailure: + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_FailedOverloadResolution: + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction); + return; + } +} + +/// Generates a 'note' diagnostic for an overload candidate. We've +/// already generated a primary error at the call site. +/// +/// It really does need to be a single diagnostic with its caret +/// pointed at the candidate declaration. Yes, this creates some +/// major challenges of technical writing. Yes, this makes pointing +/// out problems with specific arguments quite awkward. It's still +/// better than generating twenty screens of text for every failed +/// overload. +/// +/// It would be great to be able to express per-candidate problems +/// more richly for those diagnostic clients that cared, but we'd +/// still have to be just as careful with the default diagnostics. void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, Expr **Args, unsigned NumArgs) { FunctionDecl *Fn = Cand->Function; @@ -4546,6 +4659,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, return DiagnoseArityMismatch(S, Cand, NumArgs); case ovl_fail_bad_deduction: + return DiagnoseBadDeduction(S, Cand, Args, NumArgs); + case ovl_fail_trivial_conversion: case ovl_fail_bad_final_conversion: return S.NoteOverloadCandidate(Fn); @@ -4651,8 +4766,8 @@ struct CompareOverloadCandidatesForDisplay { // TODO: introduce a tri-valued comparison for overload // candidates. Would be more worthwhile if we had a sort // that could exploit it. - if (S.isBetterOverloadCandidate(*L, *R)) return true; - if (S.isBetterOverloadCandidate(*R, *L)) return false; + if (S.isBetterOverloadCandidate(*L, *R, SourceLocation())) return true; + if (S.isBetterOverloadCandidate(*R, *L, SourceLocation())) return false; } else if (R->Viable) return false; @@ -4842,6 +4957,14 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, } } +static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, NamedDecl *D, + AccessSpecifier AS) { + if (isa<UnresolvedLookupExpr>(E)) + return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D, AS); + + return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D, AS); +} + /// ResolveAddressOfOverloadedFunction - Try to resolve the address of /// an overloaded function (C++ [over.over]), where @p From is an /// expression with overloaded function type and @p ToType is the type @@ -4878,52 +5001,28 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; // Find the actual overloaded function declaration. + if (From->getType() != Context.OverloadTy) + return 0; // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] - Expr *OvlExpr = From->IgnoreParens(); - // C++ [over.over]p1: // [...] The overloaded function name can be preceded by the & // operator. - if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) { - if (UnOp->getOpcode() == UnaryOperator::AddrOf) - OvlExpr = UnOp->getSubExpr()->IgnoreParens(); + OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer(); + TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0; + if (OvlExpr->hasExplicitTemplateArgs()) { + OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer); + ExplicitTemplateArgs = &ETABuffer; } - bool HasExplicitTemplateArgs = false; - TemplateArgumentListInfo ExplicitTemplateArgs; - - llvm::SmallVector<NamedDecl*,8> Fns; - - // Look into the overloaded expression. - if (UnresolvedLookupExpr *UL - = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) { - Fns.append(UL->decls_begin(), UL->decls_end()); - if (UL->hasExplicitTemplateArgs()) { - HasExplicitTemplateArgs = true; - UL->copyTemplateArgumentsInto(ExplicitTemplateArgs); - } - } else if (UnresolvedMemberExpr *ME - = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) { - Fns.append(ME->decls_begin(), ME->decls_end()); - if (ME->hasExplicitTemplateArgs()) { - HasExplicitTemplateArgs = true; - ME->copyTemplateArgumentsInto(ExplicitTemplateArgs); - } - } - - // If we didn't actually find anything, we're done. - if (Fns.empty()) - return 0; - // Look through all of the overloaded functions, searching for one // whose type matches exactly. - llvm::SmallPtrSet<FunctionDecl *, 4> Matches; + UnresolvedSet<4> Matches; // contains only FunctionDecls bool FoundNonTemplateFunction = false; - for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(), - E = Fns.end(); I != E; ++I) { + for (UnresolvedSetIterator I = OvlExpr->decls_begin(), + E = OvlExpr->decls_end(); I != E; ++I) { // Look through any using declarations to find the underlying function. NamedDecl *Fn = (*I)->getUnderlyingDecl(); @@ -4953,10 +5052,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // overloaded functions considered. // FIXME: We don't really want to build the specialization here, do we? FunctionDecl *Specialization = 0; - TemplateDeductionInfo Info(Context); + TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc()); if (TemplateDeductionResult Result - = DeduceTemplateArguments(FunctionTemplate, - (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0), + = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, FunctionType, Specialization, Info)) { // FIXME: make a note of the failed deduction for diagnostics. (void)Result; @@ -4965,8 +5063,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // a candidate? Find a testcase before changing the code. assert(FunctionType == Context.getCanonicalType(Specialization->getType())); - Matches.insert( - cast<FunctionDecl>(Specialization->getCanonicalDecl())); + Matches.addDecl(cast<FunctionDecl>(Specialization->getCanonicalDecl()), + I.getAccess()); } continue; @@ -4979,7 +5077,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, continue; // If we have explicit template arguments, skip non-templates. - if (HasExplicitTemplateArgs) + if (OvlExpr->hasExplicitTemplateArgs()) continue; } else if (IsMember) continue; @@ -4989,7 +5087,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, ResultTy)) { - Matches.insert(cast<FunctionDecl>(FunDecl->getCanonicalDecl())); + Matches.addDecl(cast<FunctionDecl>(FunDecl->getCanonicalDecl()), + I.getAccess()); FoundNonTemplateFunction = true; } } @@ -4999,14 +5098,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Matches.empty()) return 0; else if (Matches.size() == 1) { - FunctionDecl *Result = *Matches.begin(); + FunctionDecl *Result = cast<FunctionDecl>(*Matches.begin()); MarkDeclarationReferenced(From->getLocStart(), Result); + if (Complain) + CheckUnresolvedAccess(*this, OvlExpr, Result, Matches.begin().getAccess()); return Result; } // C++ [over.over]p4: // If more than one function is selected, [...] - typedef llvm::SmallPtrSet<FunctionDecl *, 4>::iterator MatchIter; if (!FoundNonTemplateFunction) { // [...] and any given function template specialization F1 is // eliminated if the set contains a second function template @@ -5018,41 +5118,50 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // two-pass algorithm (similar to the one used to identify the // best viable function in an overload set) that identifies the // best function template (if it exists). - llvm::SmallVector<FunctionDecl *, 8> TemplateMatches(Matches.begin(), - Matches.end()); - FunctionDecl *Result = - getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(), + + UnresolvedSetIterator Result = + getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, From->getLocStart(), PDiag(), PDiag(diag::err_addr_ovl_ambiguous) - << TemplateMatches[0]->getDeclName(), + << Matches[0]->getDeclName(), PDiag(diag::note_ovl_candidate) << (unsigned) oc_function_template); - MarkDeclarationReferenced(From->getLocStart(), Result); - return Result; + assert(Result != Matches.end() && "no most-specialized template"); + MarkDeclarationReferenced(From->getLocStart(), *Result); + if (Complain) + CheckUnresolvedAccess(*this, OvlExpr, *Result, Result.getAccess()); + return cast<FunctionDecl>(*Result); } // [...] any function template specializations in the set are // eliminated if the set also contains a non-template function, [...] - llvm::SmallVector<FunctionDecl *, 4> RemainingMatches; - for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M) - if ((*M)->getPrimaryTemplate() == 0) - RemainingMatches.push_back(*M); + for (unsigned I = 0, N = Matches.size(); I != N; ) { + if (cast<FunctionDecl>(Matches[I].getDecl())->getPrimaryTemplate() == 0) + ++I; + else { + Matches.erase(I); + --N; + } + } // [...] After such eliminations, if any, there shall remain exactly one // selected function. - if (RemainingMatches.size() == 1) { - FunctionDecl *Result = RemainingMatches.front(); - MarkDeclarationReferenced(From->getLocStart(), Result); - return Result; + if (Matches.size() == 1) { + UnresolvedSetIterator Match = Matches.begin(); + MarkDeclarationReferenced(From->getLocStart(), *Match); + if (Complain) + CheckUnresolvedAccess(*this, OvlExpr, *Match, Match.getAccess()); + return cast<FunctionDecl>(*Match); } // FIXME: We should probably return the same thing that BestViableFunction // returns (even if we issue the diagnostics here). Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) - << RemainingMatches[0]->getDeclName(); - for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I) - NoteOverloadCandidate(RemainingMatches[I]); + << Matches[0]->getDeclName(); + for (UnresolvedSetIterator I = Matches.begin(), + E = Matches.end(); I != E; ++I) + NoteOverloadCandidate(cast<FunctionDecl>(*I)); return 0; } @@ -5067,47 +5176,27 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] - Expr *OvlExpr = From->IgnoreParens(); - // C++ [over.over]p1: // [...] The overloaded function name can be preceded by the & // operator. - if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) { - if (UnOp->getOpcode() == UnaryOperator::AddrOf) - OvlExpr = UnOp->getSubExpr()->IgnoreParens(); - } - - bool HasExplicitTemplateArgs = false; - TemplateArgumentListInfo ExplicitTemplateArgs; - - llvm::SmallVector<NamedDecl*,8> Fns; - - // Look into the overloaded expression. - if (UnresolvedLookupExpr *UL - = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) { - Fns.append(UL->decls_begin(), UL->decls_end()); - if (UL->hasExplicitTemplateArgs()) { - HasExplicitTemplateArgs = true; - UL->copyTemplateArgumentsInto(ExplicitTemplateArgs); - } - } else if (UnresolvedMemberExpr *ME - = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) { - Fns.append(ME->decls_begin(), ME->decls_end()); - if (ME->hasExplicitTemplateArgs()) { - HasExplicitTemplateArgs = true; - ME->copyTemplateArgumentsInto(ExplicitTemplateArgs); - } - } + + if (From->getType() != Context.OverloadTy) + return 0; + + OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer(); // If we didn't actually find any template-ids, we're done. - if (Fns.empty() || !HasExplicitTemplateArgs) + if (!OvlExpr->hasExplicitTemplateArgs()) return 0; + + TemplateArgumentListInfo ExplicitTemplateArgs; + OvlExpr->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs); // Look through all of the overloaded functions, searching for one // whose type matches exactly. FunctionDecl *Matched = 0; - for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(), - E = Fns.end(); I != E; ++I) { + for (UnresolvedSetIterator I = OvlExpr->decls_begin(), + E = OvlExpr->decls_end(); I != E; ++I) { // C++0x [temp.arg.explicit]p3: // [...] In contexts where deduction is done and fails, or in contexts // where deduction is not done, if a template argument list is @@ -5123,7 +5212,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { // function template specialization, which is added to the set of // overloaded functions considered. FunctionDecl *Specialization = 0; - TemplateDeductionInfo Info(Context); + TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc()); if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, Specialization, Info)) { @@ -5145,6 +5234,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { /// \brief Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, NamedDecl *Callee, + AccessSpecifier Access, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, @@ -5154,14 +5244,14 @@ static void AddOverloadedCallCandidate(Sema &S, if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) { assert(!ExplicitTemplateArgs && "Explicit template arguments?"); - S.AddOverloadCandidate(Func, Args, NumArgs, CandidateSet, false, false, - PartialOverloading); + S.AddOverloadCandidate(Func, Access, Args, NumArgs, CandidateSet, + false, false, PartialOverloading); return; } if (FunctionTemplateDecl *FuncTemplate = dyn_cast<FunctionTemplateDecl>(Callee)) { - S.AddTemplateOverloadCandidate(FuncTemplate, ExplicitTemplateArgs, + S.AddTemplateOverloadCandidate(FuncTemplate, Access, ExplicitTemplateArgs, Args, NumArgs, CandidateSet); return; } @@ -5217,12 +5307,13 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), E = ULE->decls_end(); I != E; ++I) - AddOverloadedCallCandidate(*this, *I, ExplicitTemplateArgs, + AddOverloadedCallCandidate(*this, *I, I.getAccess(), ExplicitTemplateArgs, Args, NumArgs, CandidateSet, PartialOverloading); if (ULE->requiresADL()) - AddArgumentDependentLookupCandidates(ULE->getName(), Args, NumArgs, + AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false, + Args, NumArgs, ExplicitTemplateArgs, CandidateSet, PartialOverloading); @@ -5321,7 +5412,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, } #endif - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(Fn->getExprLoc()); // Add the functions denoted by the callee to the set of candidate // functions, including those from argument-dependent lookup. @@ -5338,6 +5429,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) { case OR_Success: { FunctionDecl *FDecl = Best->Function; + CheckUnresolvedLookupAccess(ULE, FDecl, Best->getAccess()); Fn = FixOverloadedFunctionReference(Fn, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } @@ -5372,7 +5464,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, return ExprError(); } -static bool IsOverloaded(const Sema::FunctionSet &Functions) { +static bool IsOverloaded(const UnresolvedSetImpl &Functions) { return Functions.size() > 1 || (Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin())); } @@ -5393,10 +5485,10 @@ static bool IsOverloaded(const Sema::FunctionSet &Functions) { /// by CreateOverloadedUnaryOp(). /// /// \param input The input argument. -Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, - unsigned OpcIn, - FunctionSet &Functions, - ExprArg input) { +Sema::OwningExprResult +Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, + const UnresolvedSetImpl &Fns, + ExprArg input) { UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn); Expr *Input = (Expr *)input.get(); @@ -5418,14 +5510,12 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, } if (Input->isTypeDependent()) { + CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, + = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, OpLoc, - /*ADL*/ true, IsOverloaded(Functions)); - for (FunctionSet::iterator Func = Functions.begin(), - FuncEnd = Functions.end(); - Func != FuncEnd; ++Func) - Fn->addDecl(*Func); + /*ADL*/ true, IsOverloaded(Fns)); + Fn->addDecls(Fns.begin(), Fns.end()); input.release(); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, @@ -5435,14 +5525,20 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, } // Build an empty overload set. - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(OpLoc); // Add the candidates from the given function set. - AddFunctionCandidates(Functions, &Args[0], NumArgs, CandidateSet, false); + AddFunctionCandidates(Fns, &Args[0], NumArgs, CandidateSet, false); // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + // Add candidates from ADL. + AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, + Args, NumArgs, + /*ExplicitTemplateArgs*/ 0, + CandidateSet); + // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); @@ -5459,6 +5555,8 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { + CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess()); + if (PerformObjectArgumentInitialization(Input, Method)) return ExprError(); } else { @@ -5555,7 +5653,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, Sema::OwningExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, unsigned OpcIn, - FunctionSet &Functions, + const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS) { Expr *Args[2] = { LHS, RHS }; LHS=RHS=0; //Please use only Args instead of LHS/RHS couple @@ -5567,7 +5665,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // If either side is type-dependent, create an appropriate dependent // expression. if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { - if (Functions.empty()) { + if (Fns.empty()) { // If there are no functions to store, just build a dependent // BinaryOperator or CompoundAssignment. if (Opc <= BinaryOperator::Assign || Opc > BinaryOperator::OrAssign) @@ -5580,17 +5678,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Context.DependentTy, OpLoc)); } - + + // FIXME: save results of ADL from here? + CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, + = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, OpLoc, - /* ADL */ true, IsOverloaded(Functions)); - - for (FunctionSet::iterator Func = Functions.begin(), - FuncEnd = Functions.end(); - Func != FuncEnd; ++Func) - Fn->addDecl(*Func); + /*ADL*/ true, IsOverloaded(Fns)); + Fn->addDecls(Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args, 2, Context.DependentTy, @@ -5612,14 +5708,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); // Build an empty overload set. - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(OpLoc); // Add the candidates from the given function set. - AddFunctionCandidates(Functions, Args, 2, CandidateSet, false); + AddFunctionCandidates(Fns, Args, 2, CandidateSet, false); // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); + // Add candidates from ADL. + AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, + Args, 2, + /*ExplicitTemplateArgs*/ 0, + CandidateSet); + // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); @@ -5636,6 +5738,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { + // Best->Access is only meaningful for class members. + CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess()); + OwningExprResult Arg1 = PerformCopyInitialization( InitializedEntity::InitializeParameter( @@ -5770,8 +5875,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // expression. if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { + CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, + = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, LLoc, /*ADL*/ true, /*Overloaded*/ false); // Can't add any actual overloads yet @@ -5785,7 +5891,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, } // Build an empty overload set. - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(LLoc); // Subscript can only be overloaded as a member function. @@ -5806,14 +5912,24 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // We matched an overloaded operator. Build a call to that // operator. + CheckMemberOperatorAccess(LLoc, Args[0], FnDecl, Best->getAccess()); + // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); - if (PerformObjectArgumentInitialization(Args[0], Method) || - PerformCopyInitialization(Args[1], - FnDecl->getParamDecl(0)->getType(), - AA_Passing)) + if (PerformObjectArgumentInitialization(Args[0], Method)) return ExprError(); + // Convert the arguments. + OwningExprResult InputInit + = PerformCopyInitialization(InitializedEntity::InitializeParameter( + FnDecl->getParamDecl(0)), + SourceLocation(), + Owned(Args[1])); + if (InputInit.isInvalid()) + return ExprError(); + + Args[1] = InputInit.takeAs<Expr>(); + // Determine the result type QualType ResultTy = FnDecl->getType()->getAs<FunctionType>()->getResultType(); @@ -5914,7 +6030,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, QualType ObjectType = UnresExpr->getBaseType(); // Add overload candidates - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc()); // FIXME: avoid copy. TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; @@ -5937,11 +6053,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if (TemplateArgs) continue; - AddMethodCandidate(Method, ActingDC, ObjectType, Args, NumArgs, + AddMethodCandidate(Method, I.getAccess(), ActingDC, ObjectType, + Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); } else { AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func), - ActingDC, TemplateArgs, + I.getAccess(), ActingDC, TemplateArgs, ObjectType, Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); @@ -5954,6 +6071,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { case OR_Success: Method = cast<CXXMethodDecl>(Best->Function); + CheckUnresolvedMemberAccess(UnresExpr, Method, Best->getAccess()); break; case OR_No_Viable_Function: @@ -6043,7 +6161,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // operators of T. The function call operators of T are obtained by // ordinary lookup of the name operator() in the context of // (E).operator(). - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(LParenLoc); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); if (RequireCompleteType(LParenLoc, Object->getType(), @@ -6057,7 +6175,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - AddMethodCandidate(*Oper, Object->getType(), Args, NumArgs, CandidateSet, + AddMethodCandidate(*Oper, Oper.getAccess(), Object->getType(), + Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } @@ -6101,7 +6220,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, ConvType = ConvPtrType->getPointeeType(); if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) - AddSurrogateCandidate(Conv, ActingContext, Proto, + AddSurrogateCandidate(Conv, I.getAccess(), ActingContext, Proto, Object->getType(), Args, NumArgs, CandidateSet); } @@ -6158,6 +6277,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, = cast<CXXConversionDecl>( Best->Conversions[0].UserDefined.ConversionFunction); + CheckMemberOperatorAccess(LParenLoc, Object, Conv, Best->getAccess()); + // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion // on the object argument, then let ActOnCallExpr finish the job. @@ -6171,6 +6292,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, CommaLocs, RParenLoc).release(); } + CheckMemberOperatorAccess(LParenLoc, Object, + Best->Function, Best->getAccess()); + // We found an overloaded operator(). Build a CXXOperatorCallExpr // that calls this method, using Object for the implicit object // parameter and passing along the remaining arguments. @@ -6232,8 +6356,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, Arg = Args[i]; // Pass the argument. - QualType ProtoArgType = Proto->getArgType(i); - IsError |= PerformCopyInitialization(Arg, ProtoArgType, AA_Passing); + + OwningExprResult InputInit + = PerformCopyInitialization(InitializedEntity::InitializeParameter( + Method->getParamDecl(i)), + SourceLocation(), Owned(Arg)); + + IsError |= InputInit.isInvalid(); + Arg = InputInit.takeAs<Expr>(); } else { OwningExprResult DefArg = BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i)); @@ -6274,6 +6404,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { Expr *Base = static_cast<Expr *>(BaseIn.get()); assert(Base->getType()->isRecordType() && "left-hand side must have class type"); + SourceLocation Loc = Base->getExprLoc(); + // C++ [over.ref]p1: // // [...] An expression x->m is interpreted as (x.operator->())->m @@ -6281,10 +6413,10 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { // the operator is selected as the best match function by the // overload resolution mechanism (13.3). DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow); - OverloadCandidateSet CandidateSet; + OverloadCandidateSet CandidateSet(Loc); const RecordType *BaseRecord = Base->getType()->getAs<RecordType>(); - if (RequireCompleteType(Base->getLocStart(), Base->getType(), + if (RequireCompleteType(Loc, Base->getType(), PDiag(diag::err_typecheck_incomplete_tag) << Base->getSourceRange())) return ExprError(); @@ -6300,7 +6432,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - AddMethodCandidate(cast<CXXMethodDecl>(D), ActingContext, + AddMethodCandidate(cast<CXXMethodDecl>(D), Oper.getAccess(), ActingContext, Base->getType(), 0, 0, CandidateSet, /*SuppressUserConversions=*/false); } diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index f8353e3db1bd..e6dfa742355f 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -139,9 +139,10 @@ namespace clang { /// QualType. void *FromTypePtr; - /// ToType - The type that this conversion is converting to. This - /// is an opaque pointer that can be translated into a QualType. - void *ToTypePtr; + /// ToType - The types that this conversion is converting to in + /// each step. This is an opaque pointer that can be translated + /// into a QualType. + void *ToTypePtrs[3]; /// CopyConstructor - The copy constructor that is used to perform /// this conversion, when the conversion is actually just the @@ -151,12 +152,22 @@ namespace clang { CXXConstructorDecl *CopyConstructor; void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } - void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + void setToType(unsigned Idx, QualType T) { + assert(Idx < 3 && "To type index is out of range"); + ToTypePtrs[Idx] = T.getAsOpaquePtr(); + } + void setAllToTypes(QualType T) { + ToTypePtrs[0] = T.getAsOpaquePtr(); + ToTypePtrs[1] = ToTypePtrs[0]; + ToTypePtrs[2] = ToTypePtrs[0]; + } + QualType getFromType() const { return QualType::getFromOpaquePtr(FromTypePtr); } - QualType getToType() const { - return QualType::getFromOpaquePtr(ToTypePtr); + QualType getToType(unsigned Idx) const { + assert(Idx < 3 && "To type index is out of range"); + return QualType::getFromOpaquePtr(ToTypePtrs[Idx]); } void setAsIdentityConversion(); @@ -446,11 +457,33 @@ namespace clang { /// Actually an OverloadFailureKind. unsigned char FailureKind; - /// FinalConversion - For a conversion function (where Function is - /// a CXXConversionDecl), the standard conversion that occurs - /// after the call to the overload candidate to convert the result - /// of calling the conversion function to the required type. - StandardConversionSequence FinalConversion; + /// PathAccess - The 'path access' to the given function/conversion. + /// Actually an AccessSpecifier. + unsigned Access; + + AccessSpecifier getAccess() const { + return AccessSpecifier(Access); + } + + /// A structure used to record information about a failed + /// template argument deduction. + struct DeductionFailureInfo { + // A Sema::TemplateDeductionResult. + unsigned Result; + + // A TemplateParameter. + void *TemplateParameter; + }; + + union { + DeductionFailureInfo DeductionFailure; + + /// FinalConversion - For a conversion function (where Function is + /// a CXXConversionDecl), the standard conversion that occurs + /// after the call to the overload candidate to convert the result + /// of calling the conversion function to the required type. + StandardConversionSequence FinalConversion; + }; /// hasAmbiguousConversion - Returns whether this overload /// candidate requires an ambiguous conversion or not. @@ -468,8 +501,13 @@ namespace clang { class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> { typedef llvm::SmallVector<OverloadCandidate, 16> inherited; llvm::SmallPtrSet<Decl *, 16> Functions; - + + SourceLocation Loc; public: + OverloadCandidateSet(SourceLocation Loc) : Loc(Loc) {} + + SourceLocation getLocation() const { return Loc; } + /// \brief Determine when this overload candidate will be new to the /// overload set. bool isNewCandidate(Decl *F) { diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 0c207fa6e87d..fa42634a3475 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -93,6 +93,15 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (isa<ObjCImplicitSetterGetterRefExpr>(E)) DiagID = diag::warn_unused_property_expr; + if (const CXXExprWithTemporaries *Temps = dyn_cast<CXXExprWithTemporaries>(E)) + E = Temps->getSubExpr(); + if (const CXXZeroInitValueExpr *Zero = dyn_cast<CXXZeroInitValueExpr>(E)) { + if (const RecordType *RecordT = Zero->getType()->getAs<RecordType>()) + if (CXXRecordDecl *RecordD = dyn_cast<CXXRecordDecl>(RecordT->getDecl())) + if (!RecordD->hasTrivialDestructor()) + return; + } + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { // If the callee has attribute pure, const, or warn_unused_result, warn with // a more specific message to make it clear what is happening. @@ -370,6 +379,22 @@ static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs, return false; } +/// CmpEnumVals - Comparison predicate for sorting enumeration values. +/// +static bool CmpEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs, + const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs) +{ + return lhs.first < rhs.first; +} + +/// EqEnumVals - Comparison preficate for uniqing enumeration values. +/// +static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs, + const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs) +{ + return lhs.first == rhs.first; +} + /// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of /// potentially integral-promoted expression @p expr. static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { @@ -482,6 +507,16 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, return false; } +/// ActOnSwitchBodyError - This is called if there is an error parsing the +/// body of the switch stmt instead of ActOnFinishSwitchStmt. +void Sema::ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, + StmtArg Body) { + // Keep the switch stack balanced. + assert(getSwitchStack().back() == (SwitchStmt*)Switch.get() && + "switch stack missing push/pop!"); + getSwitchStack().pop_back(); +} + Action::OwningStmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body) { @@ -550,7 +585,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, CaseValsTy CaseVals; // Keep track of any GNU case ranges we see. The APSInt is the low value. - std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges; + typedef std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRangesTy; + CaseRangesTy CaseRanges; DefaultStmt *TheDefaultStmt = 0; @@ -713,6 +749,75 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } } } + + // Check to see if switch is over an Enum and handles all of its + // values + const EnumType* ET = dyn_cast<EnumType>(CondTypeBeforePromotion); + // If switch has default case, then ignore it. + if (!CaseListIsErroneous && !TheDefaultStmt && ET) { + const EnumDecl *ED = ET->getDecl(); + typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; + EnumValsTy EnumVals; + + // Gather all enum values, set their type and sort them, allowing easier comparison + // with CaseVals. + for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); EDI != ED->enumerator_end(); EDI++) { + llvm::APSInt Val = (*EDI)->getInitVal(); + if(Val.getBitWidth() < CondWidth) + Val.extend(CondWidth); + Val.setIsSigned(CondIsSigned); + EnumVals.push_back(std::make_pair(Val, (*EDI))); + } + std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); + EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); + // See which case values aren't in enum + EnumValsTy::const_iterator EI = EnumVals.begin(); + for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) { + while (EI != EIend && EI->first < CI->first) + EI++; + if (EI == EIend || EI->first > CI->first) + Diag(CI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName(); + } + // See which of case ranges aren't in enum + EI = EnumVals.begin(); + for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end() && EI != EIend; RI++) { + while (EI != EIend && EI->first < RI->first) + EI++; + + if (EI == EIend || EI->first != RI->first) { + Diag(RI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName(); + } + + llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); + while (EI != EIend && EI->first < Hi) + EI++; + if (EI == EIend || EI->first != Hi) + Diag(RI->second->getRHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName(); + } + //Check which enum vals aren't in switch + CaseValsTy::const_iterator CI = CaseVals.begin(); + CaseRangesTy::const_iterator RI = CaseRanges.begin(); + EI = EnumVals.begin(); + for (; EI != EIend; EI++) { + //Drop unneeded case values + llvm::APSInt CIVal; + while (CI != CaseVals.end() && CI->first < EI->first) + CI++; + + if (CI != CaseVals.end() && CI->first == EI->first) + continue; + + //Drop unneeded case ranges + for (; RI != CaseRanges.end(); RI++) { + llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); + if (EI->first <= Hi) + break; + } + + if (RI == CaseRanges.end() || EI->first < RI->first) + Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) << EI->second->getDeclName(); + } + } } // FIXME: If the case list was broken is some way, we don't have a good system @@ -863,7 +968,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, << FirstType << First->getSourceRange(); } if (Second) { - DefaultFunctionArrayConversion(Second); + DefaultFunctionArrayLvalueConversion(Second); QualType SecondType = Second->getType(); if (!SecondType->isObjCObjectPointerType()) Diag(ForLoc, diag::err_collection_expr_type) @@ -896,10 +1001,10 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, Expr* E = DestExp.takeAs<Expr>(); if (!E->isTypeDependent()) { QualType ETy = E->getType(); + QualType DestTy = Context.getPointerType(Context.VoidTy.withConst()); AssignConvertType ConvTy = - CheckSingleAssignmentConstraints(Context.VoidPtrTy, E); - if (DiagnoseAssignmentResult(ConvTy, StarLoc, Context.VoidPtrTy, ETy, - E, AA_Passing)) + CheckSingleAssignmentConstraints(DestTy, E); + if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing)) return StmtError(); } return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E)); @@ -937,7 +1042,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (RetValExp) { // Don't call UsualUnaryConversions(), since we don't want to do // integer promotions here. - DefaultFunctionArrayConversion(RetValExp); + DefaultFunctionArrayLvalueConversion(RetValExp); CurBlock->ReturnType = RetValExp->getType(); if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) { // We have to remove a 'const' added to copied-in variable which was @@ -981,11 +1086,19 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - // FIXME: Leaks RetValExp. - if (PerformCopyInitialization(RetValExp, FnRetType, AA_Returning)) + OwningExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeResult(ReturnLoc, + FnRetType), + SourceLocation(), + Owned(RetValExp)); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? return StmtError(); - - if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + } + + RetValExp = Res.takeAs<Expr>(); + if (RetValExp) + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); @@ -1025,7 +1138,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { QualType FnRetType; if (const FunctionDecl *FD = getCurFunctionDecl()) { FnRetType = FD->getResultType(); - if (FD->hasAttr<NoReturnAttr>()) + if (FD->hasAttr<NoReturnAttr>() || + FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << getCurFunctionOrMethodDecl()->getDeclName(); } else if (ObjCMethodDecl *MD = getCurMethodDecl()) @@ -1121,6 +1235,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { /// This method checks to see if the argument is an acceptable l-value and /// returns false if it is a case we can handle. static bool CheckAsmLValue(const Expr *E, Sema &S) { + // Type dependent expressions will be checked during instantiation. + if (E->isTypeDependent()) + return false; + if (E->isLvalue(S.Context) == Expr::LV_Valid) return false; // Cool, this is an lvalue. @@ -1148,7 +1266,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, - std::string *Names, + IdentifierInfo **Names, MultiExprArg constraints, MultiExprArg exprs, ExprArg asmString, @@ -1175,9 +1293,11 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - TargetInfo::ConstraintInfo Info(Literal->getStrData(), - Literal->getByteLength(), - Names[i]); + llvm::StringRef OutputName; + if (Names[i]) + OutputName = Names[i]->getName(); + + TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); if (!Context.Target.validateOutputConstraint(Info)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_output_constraint) @@ -1202,9 +1322,11 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - TargetInfo::ConstraintInfo Info(Literal->getStrData(), - Literal->getByteLength(), - Names[i]); + llvm::StringRef InputName; + if (Names[i]) + InputName = Names[i]->getName(); + + TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(), NumOutputs, Info)) { return StmtError(Diag(Literal->getLocStart(), @@ -1232,7 +1354,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, } } - DefaultFunctionArrayConversion(Exprs[i]); + DefaultFunctionArrayLvalueConversion(Exprs[i]); InputConstraintInfos.push_back(Info); } @@ -1244,11 +1366,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - std::string Clobber(Literal->getStrData(), - Literal->getStrData() + - Literal->getByteLength()); + llvm::StringRef Clobber = Literal->getString(); - if (!Context.Target.isValidGCCRegisterName(Clobber.c_str())) + if (!Context.Target.isValidGCCRegisterName(Clobber)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_unknown_register_name) << Clobber); } @@ -1258,9 +1378,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, asmString.release(); clobbers.release(); AsmStmt *NS = - new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, MSAsm, NumOutputs, - NumInputs, Names, Constraints, Exprs, AsmString, - NumClobbers, Clobbers, RParenLoc); + new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm, + NumOutputs, NumInputs, Names, Constraints, Exprs, + AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces; @@ -1527,7 +1647,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock, CurFunctionNeedsScopeChecking = true; RawHandlers.release(); - return Owned(new (Context) CXXTryStmt(TryLoc, - static_cast<Stmt*>(TryBlock.release()), - Handlers, NumHandlers)); + return Owned(CXXTryStmt::Create(Context, TryLoc, + static_cast<Stmt*>(TryBlock.release()), + Handlers, NumHandlers)); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 00401560c6a0..10e411f5825a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -823,7 +823,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Check for redefinition of this class template. if (TUK == TUK_Definition) { - if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) { + if (TagDecl *Def = PrevRecordDecl->getDefinition()) { Diag(NameLoc, diag::err_redefinition) << Name; Diag(Def->getLocation(), diag::note_previous_definition); // FIXME: Would it make sense to try to "forget" the previous @@ -1235,18 +1235,14 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // such a member, the member declaration shall be preceded by a // template<> for each enclosing class template that is // explicitly specialized. - // We interpret this as forbidding typedefs of template - // specializations in the scope specifiers of out-of-line decls. - if (const TypedefType *TT = dyn_cast<TypedefType>(T)) { - const Type *UnderlyingT = TT->LookThroughTypedefs().getTypePtr(); - if (isa<TemplateSpecializationType>(UnderlyingT)) - // FIXME: better source location information. - Diag(DeclStartLoc, diag::err_typedef_in_def_scope) << QualType(T,0); - T = UnderlyingT; - } + // + // Following the existing practice of GNU and EDG, we allow a typedef of a + // template specialization type. + if (const TypedefType *TT = dyn_cast<TypedefType>(T)) + T = TT->LookThroughTypedefs().getTypePtr(); if (const TemplateSpecializationType *SpecType - = dyn_cast<TemplateSpecializationType>(T)) { + = dyn_cast<TemplateSpecializationType>(T)) { TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl(); if (!Template) continue; // FIXME: should this be an error? probably... @@ -1525,17 +1521,19 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); QualifierRange = SS.getRange(); } + + // We don't want lookup warnings at this point. + R.suppressDiagnostics(); bool Dependent = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), &TemplateArgs); UnresolvedLookupExpr *ULE - = UnresolvedLookupExpr::Create(Context, Dependent, + = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(), Qualifier, QualifierRange, R.getLookupName(), R.getNameLoc(), RequiresADL, TemplateArgs); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - ULE->addDecl(*I); + ULE->addDecls(R.begin(), R.end()); return Owned(ULE); } @@ -2305,7 +2303,17 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, } else DRE = dyn_cast<DeclRefExpr>(Arg); - if (!DRE || !isa<ValueDecl>(DRE->getDecl())) + if (!DRE) + return Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_decl_ref) + << Arg->getSourceRange(); + + // Stop checking the precise nature of the argument if it is value dependent, + // it should be checked when instantiated. + if (Arg->isValueDependent()) + return false; + + if (!isa<ValueDecl>(DRE->getDecl())) return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_object_or_func_form) << Arg->getSourceRange(); @@ -2324,7 +2332,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, // Functions must have external linkage. if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) { - if (Func->getLinkage() != NamedDecl::ExternalLinkage) { + if (!isExternalLinkage(Func->getLinkage())) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_function_not_extern) << Func << Arg->getSourceRange(); @@ -2339,7 +2347,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, } if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { - if (Var->getLinkage() != NamedDecl::ExternalLinkage) { + if (!isExternalLinkage(Var->getLinkage())) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_object_not_extern) << Var << Arg->getSourceRange(); @@ -2656,9 +2664,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - if (Entity) - Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); + if (Arg->isValueDependent()) { + Converted = TemplateArgument(Arg); + } else { + if (Entity) + Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); + Converted = TemplateArgument(Entity); + } return false; } @@ -2696,9 +2708,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - if (Entity) - Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); + if (Arg->isValueDependent()) { + Converted = TemplateArgument(Arg); + } else { + if (Entity) + Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); + Converted = TemplateArgument(Entity); + } return false; } @@ -2712,7 +2728,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamRefType->getPointeeType()->isObjectType() && "Only object references allowed here"); - if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) { + QualType ReferredType = ParamRefType->getPointeeType(); + if (!Context.hasSameUnqualifiedType(ReferredType, ArgType)) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_no_ref_bind) << InstantiatedParamType << Arg->getType() @@ -2722,7 +2739,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } unsigned ParamQuals - = Context.getCanonicalType(ParamType).getCVRQualifiers(); + = Context.getCanonicalType(ReferredType).getCVRQualifiers(); unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers(); if ((ParamQuals | ArgQuals) != ParamQuals) { @@ -2738,8 +2755,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); + if (Arg->isValueDependent()) { + Converted = TemplateArgument(Arg); + } else { + Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); + Converted = TemplateArgument(Entity); + } return false; } @@ -3375,12 +3396,23 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // FIXME: Diagnose friend partial specializations - // FIXME: Template parameter list matters, too - ClassTemplatePartialSpecializationDecl::Profile(ID, - Converted.getFlatArguments(), - Converted.flatSize(), - Context); - } else + if (!Name.isDependent() && + !TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs.getArgumentArray(), + TemplateArgs.size())) { + Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) + << ClassTemplate->getDeclName(); + isPartialSpecialization = false; + } else { + // FIXME: Template parameter list matters, too + ClassTemplatePartialSpecializationDecl::Profile(ID, + Converted.getFlatArguments(), + Converted.flatSize(), + Context); + } + } + + if (!isPartialSpecialization) ClassTemplateSpecializationDecl::Profile(ID, Converted.getFlatArguments(), Converted.flatSize(), @@ -3410,7 +3442,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, QualType CanonType; if (PrevDecl && (PrevDecl->getSpecializationKind() == TSK_Undeclared || - TUK == TUK_Friend)) { + TUK == TUK_Friend)) { // Since the only prior class template specialization with these // arguments was referenced but not declared, or we're only // referencing this specialization as a friend, reuse that @@ -3423,8 +3455,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } else if (isPartialSpecialization) { // Build the canonical type that describes the converted template // arguments of the class template partial specialization. - CanonType = Context.getTemplateSpecializationType( - TemplateName(ClassTemplate), + TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); + CanonType = Context.getTemplateSpecializationType(CanonTemplate, Converted.getFlatArguments(), Converted.flatSize()); @@ -3532,7 +3564,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Check that this isn't a redefinition of this specialization. if (TUK == TUK_Definition) { - if (RecordDecl *Def = Specialization->getDefinition(Context)) { + if (RecordDecl *Def = Specialization->getDefinition()) { SourceRange Range(TemplateNameLoc, RAngleLoc); Diag(TemplateNameLoc, diag::err_redefinition) << Context.getTypeDeclType(Specialization) << Range; @@ -3619,6 +3651,16 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, return DeclPtrTy(); } +/// \brief Strips various properties off an implicit instantiation +/// that has just been explicitly specialized. +static void StripImplicitInstantiation(NamedDecl *D) { + D->invalidateAttrs(); + + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + FD->setInlineSpecified(false); + } +} + /// \brief Diagnose cases where we have an explicit template specialization /// before/after an explicit template instantiation, producing diagnostics /// for those cases where they are required and determining whether the @@ -3669,6 +3711,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, if (PrevPointOfInstantiation.isInvalid()) { // The declaration itself has not actually been instantiated, so it is // still okay to specialize it. + StripImplicitInstantiation(PrevDecl); return false; } // Fall through @@ -3817,8 +3860,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, LookupResult &Previous) { // The set of function template specializations that could match this // explicit function template specialization. - typedef llvm::SmallVector<FunctionDecl *, 8> CandidateSet; - CandidateSet Candidates; + UnresolvedSet<8> Candidates; DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext(); for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); @@ -3837,7 +3879,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Perform template argument deduction to determine whether we may be // specializing this template. // FIXME: It is somewhat wasteful to build - TemplateDeductionInfo Info(Context); + TemplateDeductionInfo Info(Context, FD->getLocation()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs, @@ -3851,22 +3893,24 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, } // Record this candidate. - Candidates.push_back(Specialization); + Candidates.addDecl(Specialization, I.getAccess()); } } // Find the most specialized function template. - FunctionDecl *Specialization = getMostSpecialized(Candidates.data(), - Candidates.size(), - TPOC_Other, - FD->getLocation(), + UnresolvedSetIterator Result + = getMostSpecialized(Candidates.begin(), Candidates.end(), + TPOC_Other, FD->getLocation(), PartialDiagnostic(diag::err_function_template_spec_no_match) << FD->getDeclName(), PartialDiagnostic(diag::err_function_template_spec_ambiguous) << FD->getDeclName() << (ExplicitTemplateArgs != 0), PartialDiagnostic(diag::note_function_template_spec_matched)); - if (!Specialization) + if (Result == Candidates.end()) return true; + + // Ignore access information; it doesn't figure into redeclaration checking. + FunctionDecl *Specialization = cast<FunctionDecl>(*Result); // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . @@ -3887,15 +3931,15 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, FunctionTemplateSpecializationInfo *SpecInfo = Specialization->getTemplateSpecializationInfo(); assert(SpecInfo && "Function template specialization info missing?"); - if (SpecInfo->getPointOfInstantiation().isValid()) { - Diag(FD->getLocation(), diag::err_specialization_after_instantiation) - << FD; - Diag(SpecInfo->getPointOfInstantiation(), - diag::note_instantiation_required_here) - << (Specialization->getTemplateSpecializationKind() - != TSK_ImplicitInstantiation); + + bool SuppressNew = false; + if (CheckSpecializationInstantiationRedecl(FD->getLocation(), + TSK_ExplicitSpecialization, + Specialization, + SpecInfo->getTemplateSpecializationKind(), + SpecInfo->getPointOfInstantiation(), + SuppressNew)) return true; - } // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. @@ -3904,8 +3948,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Turn the given function declaration into a function template // specialization, with the template arguments from the previous // specialization. - FD->setFunctionTemplateSpecialization(Context, - Specialization->getPrimaryTemplate(), + FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(), new (Context) TemplateArgumentList( *Specialization->getTemplateSpecializationArgs()), /*InsertPos=*/0, @@ -3997,14 +4040,15 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. assert(MSInfo && "Member specialization info missing?"); - if (MSInfo->getPointOfInstantiation().isValid()) { - Diag(Member->getLocation(), diag::err_specialization_after_instantiation) - << Member; - Diag(MSInfo->getPointOfInstantiation(), - diag::note_instantiation_required_here) - << (MSInfo->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); + + bool SuppressNew = false; + if (CheckSpecializationInstantiationRedecl(Member->getLocation(), + TSK_ExplicitSpecialization, + Instantiation, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew)) return true; - } // Check the scope of this explicit specialization. if (CheckTemplateSpecializationScope(*this, @@ -4288,13 +4332,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, // instantiation. ClassTemplateSpecializationDecl *Def = cast_or_null<ClassTemplateSpecializationDecl>( - Specialization->getDefinition(Context)); + Specialization->getDefinition()); if (!Def) InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK); // Instantiate the members of this class template specialization. Def = cast_or_null<ClassTemplateSpecializationDecl>( - Specialization->getDefinition(Context)); + Specialization->getDefinition()); if (Def) InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); @@ -4371,7 +4415,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Verify that it is okay to explicitly instantiate here. CXXRecordDecl *PrevDecl = cast_or_null<CXXRecordDecl>(Record->getPreviousDeclaration()); - if (!PrevDecl && Record->getDefinition(Context)) + if (!PrevDecl && Record->getDefinition()) PrevDecl = Record; if (PrevDecl) { MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo(); @@ -4388,13 +4432,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, } CXXRecordDecl *RecordDef - = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context)); + = cast_or_null<CXXRecordDecl>(Record->getDefinition()); if (!RecordDef) { // C++ [temp.explicit]p3: // A definition of a member class of a class template shall be in scope // at the point of an explicit instantiation of the member class. CXXRecordDecl *Def - = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); + = cast_or_null<CXXRecordDecl>(Pattern->getDefinition()); if (!Def) { Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member) << 0 << Record->getDeclName() << Record->getDeclContext(); @@ -4407,7 +4451,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, TSK)) return true; - RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context)); + RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition()); if (!RecordDef) return true; } @@ -4568,7 +4612,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // A member function [...] of a class template can be explicitly // instantiated from the member definition associated with its class // template. - llvm::SmallVector<FunctionDecl *, 8> Matches; + UnresolvedSet<8> Matches; for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); P != PEnd; ++P) { NamedDecl *Prev = *P; @@ -4577,7 +4621,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (Context.hasSameUnqualifiedType(Method->getType(), R)) { Matches.clear(); - Matches.push_back(Method); + Matches.addDecl(Method, P.getAccess()); if (Method->getTemplateSpecializationKind() == TSK_Undeclared) break; } @@ -4588,7 +4632,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!FunTmpl) continue; - TemplateDeductionInfo Info(Context); + TemplateDeductionInfo Info(Context, D.getIdentifierLoc()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK = DeduceTemplateArguments(FunTmpl, @@ -4599,19 +4643,22 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, continue; } - Matches.push_back(Specialization); + Matches.addDecl(Specialization, P.getAccess()); } // Find the most specialized function template specialization. - FunctionDecl *Specialization - = getMostSpecialized(Matches.data(), Matches.size(), TPOC_Other, + 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)); - if (!Specialization) + if (Result == Matches.end()) return true; + + // Ignore access control bits, we don't need them for redeclaration checking. + FunctionDecl *Specialization = cast<FunctionDecl>(*Result); if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { Diag(D.getIdentifierLoc(), diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 7b433e901e33..df4d4a828d48 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -49,7 +49,7 @@ namespace clang { using namespace clang; static Sema::TemplateDeductionResult -DeduceTemplateArguments(ASTContext &Context, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument &Param, const TemplateArgument &Arg, @@ -72,7 +72,7 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { /// \brief Deduce the value of the given non-type template parameter /// from the given constant. static Sema::TemplateDeductionResult -DeduceNonTypeTemplateArgument(ASTContext &Context, +DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, llvm::APSInt Value, Sema::TemplateDeductionInfo &Info, @@ -84,7 +84,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, QualType T = NTTP->getType(); // FIXME: Make sure we didn't overflow our data type! - unsigned AllowedBits = Context.getTypeSize(T); + unsigned AllowedBits = S.Context.getTypeSize(T); if (Value.getBitWidth() != AllowedBits) Value.extOrTrunc(AllowedBits); Value.setIsSigned(T->isSignedIntegerType()); @@ -126,7 +126,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, /// /// \returns true if deduction succeeded, false otherwise. static Sema::TemplateDeductionResult -DeduceNonTypeTemplateArgument(ASTContext &Context, +DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Expr *Value, Sema::TemplateDeductionInfo &Info, @@ -152,8 +152,8 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) { // Compare the expressions for equality llvm::FoldingSetNodeID ID1, ID2; - Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, Context, true); - Value->Profile(ID2, Context, true); + Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, S.Context, true); + Value->Profile(ID2, S.Context, true); if (ID1 == ID2) return Sema::TDK_Success; @@ -169,7 +169,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, /// /// \returns true if deduction succeeded, false otherwise. static Sema::TemplateDeductionResult -DeduceNonTypeTemplateArgument(ASTContext &Context, +DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Decl *D, Sema::TemplateDeductionInfo &Info, @@ -202,7 +202,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, } static Sema::TemplateDeductionResult -DeduceTemplateArguments(ASTContext &Context, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, TemplateName Param, TemplateName Arg, @@ -221,13 +221,13 @@ DeduceTemplateArguments(ASTContext &Context, TemplateArgument &ExistingArg = Deduced[TempParam->getIndex()]; if (ExistingArg.isNull()) { // This is the first deduction for this template template parameter. - ExistingArg = TemplateArgument(Context.getCanonicalTemplateName(Arg)); + ExistingArg = TemplateArgument(S.Context.getCanonicalTemplateName(Arg)); return Sema::TDK_Success; } // Verify that the previous binding matches this deduction. assert(ExistingArg.getKind() == TemplateArgument::Template); - if (Context.hasSameTemplateName(ExistingArg.getAsTemplate(), Arg)) + if (S.Context.hasSameTemplateName(ExistingArg.getAsTemplate(), Arg)) return Sema::TDK_Success; // Inconsistent deduction. @@ -238,7 +238,7 @@ DeduceTemplateArguments(ASTContext &Context, } // Verify that the two template names are equivalent. - if (Context.hasSameTemplateName(Param, Arg)) + if (S.Context.hasSameTemplateName(Param, Arg)) return Sema::TDK_Success; // Mismatch of non-dependent template parameter to argument. @@ -250,7 +250,7 @@ DeduceTemplateArguments(ASTContext &Context, /// \brief Deduce the template arguments by comparing the template parameter /// type (which is a template-id) with the template argument type. /// -/// \param Context the AST context in which this deduction occurs. +/// \param S the Sema /// /// \param TemplateParams the template parameters that we are deducing /// @@ -266,7 +266,7 @@ DeduceTemplateArguments(ASTContext &Context, /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. static Sema::TemplateDeductionResult -DeduceTemplateArguments(ASTContext &Context, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateSpecializationType *Param, QualType Arg, @@ -279,7 +279,7 @@ DeduceTemplateArguments(ASTContext &Context, = dyn_cast<TemplateSpecializationType>(Arg)) { // Perform template argument deduction for the template name. if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, + = DeduceTemplateArguments(S, TemplateParams, Param->getTemplateName(), SpecArg->getTemplateName(), Info, Deduced)) @@ -291,7 +291,7 @@ DeduceTemplateArguments(ASTContext &Context, unsigned NumArgs = std::min(SpecArg->getNumArgs(), Param->getNumArgs()); for (unsigned I = 0; I != NumArgs; ++I) if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, + = DeduceTemplateArguments(S, TemplateParams, Param->getArg(I), SpecArg->getArg(I), Info, Deduced)) @@ -314,7 +314,7 @@ DeduceTemplateArguments(ASTContext &Context, // Perform template argument deduction for the template name. if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, + = DeduceTemplateArguments(S, TemplateParams, Param->getTemplateName(), TemplateName(SpecArg->getSpecializedTemplate()), @@ -328,7 +328,7 @@ DeduceTemplateArguments(ASTContext &Context, for (unsigned I = 0; I != NumArgs; ++I) if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, + = DeduceTemplateArguments(S, TemplateParams, Param->getArg(I), ArgArgs.get(I), Info, Deduced)) @@ -340,7 +340,7 @@ DeduceTemplateArguments(ASTContext &Context, /// \brief Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// -/// \param Context the AST context in which this deduction occurs. +/// \param S the semantic analysis object within which we are deducing /// /// \param TemplateParams the template parameters that we are deducing /// @@ -359,7 +359,7 @@ DeduceTemplateArguments(ASTContext &Context, /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. static Sema::TemplateDeductionResult -DeduceTemplateArguments(ASTContext &Context, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, QualType ParamIn, QualType ArgIn, Sema::TemplateDeductionInfo &Info, @@ -367,8 +367,8 @@ DeduceTemplateArguments(ASTContext &Context, unsigned TDF) { // We only want to look at the canonical types, since typedefs and // sugar are not part of template argument deduction. - QualType Param = Context.getCanonicalType(ParamIn); - QualType Arg = Context.getCanonicalType(ArgIn); + QualType Param = S.Context.getCanonicalType(ParamIn); + QualType Arg = S.Context.getCanonicalType(ArgIn); // C++0x [temp.deduct.call]p4 bullet 1: // - If the original P is a reference type, the deduced A (i.e., the type @@ -376,10 +376,10 @@ DeduceTemplateArguments(ASTContext &Context, // transformed A. if (TDF & TDF_ParamWithReferenceType) { Qualifiers Quals; - QualType UnqualParam = Context.getUnqualifiedArrayType(Param, Quals); + QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); Quals.setCVRQualifiers(Quals.getCVRQualifiers() & Arg.getCVRQualifiersThroughArrayTypes()); - Param = Context.getQualifiedType(UnqualParam, Quals); + Param = S.Context.getQualifiedType(UnqualParam, Quals); } // If the parameter type is not dependent, there is nothing to deduce. @@ -409,9 +409,9 @@ DeduceTemplateArguments(ASTContext &Context, // FIXME: address spaces, ObjC GC qualifiers if (isa<ArrayType>(Arg)) { Qualifiers Quals; - Arg = Context.getUnqualifiedArrayType(Arg, Quals); + Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); if (Quals) { - Arg = Context.getQualifiedType(Arg, Quals); + Arg = S.Context.getQualifiedType(Arg, Quals); RecanonicalizeArg = true; } } @@ -426,11 +426,11 @@ DeduceTemplateArguments(ASTContext &Context, } assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0"); - assert(Arg != Context.OverloadTy && "Unresolved overloaded function"); + assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); QualType DeducedType = Arg; DeducedType.removeCVRQualifiers(Param.getCVRQualifiers()); if (RecanonicalizeArg) - DeducedType = Context.getCanonicalType(DeducedType); + DeducedType = S.Context.getCanonicalType(DeducedType); if (Deduced[Index].isNull()) Deduced[Index] = TemplateArgument(DeducedType); @@ -479,7 +479,7 @@ DeduceTemplateArguments(ASTContext &Context, return Sema::TDK_NonDeducedMismatch; unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass); - return DeduceTemplateArguments(Context, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, cast<PointerType>(Param)->getPointeeType(), PointerArg->getPointeeType(), Info, Deduced, SubTDF); @@ -491,7 +491,7 @@ DeduceTemplateArguments(ASTContext &Context, if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, cast<LValueReferenceType>(Param)->getPointeeType(), ReferenceArg->getPointeeType(), Info, Deduced, 0); @@ -503,7 +503,7 @@ DeduceTemplateArguments(ASTContext &Context, if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, cast<RValueReferenceType>(Param)->getPointeeType(), ReferenceArg->getPointeeType(), Info, Deduced, 0); @@ -512,12 +512,12 @@ DeduceTemplateArguments(ASTContext &Context, // T [] (implied, but not stated explicitly) case Type::IncompleteArray: { const IncompleteArrayType *IncompleteArrayArg = - Context.getAsIncompleteArrayType(Arg); + S.Context.getAsIncompleteArrayType(Arg); if (!IncompleteArrayArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, TemplateParams, - Context.getAsIncompleteArrayType(Param)->getElementType(), + return DeduceTemplateArguments(S, TemplateParams, + S.Context.getAsIncompleteArrayType(Param)->getElementType(), IncompleteArrayArg->getElementType(), Info, Deduced, 0); } @@ -525,16 +525,16 @@ DeduceTemplateArguments(ASTContext &Context, // T [integer-constant] case Type::ConstantArray: { const ConstantArrayType *ConstantArrayArg = - Context.getAsConstantArrayType(Arg); + S.Context.getAsConstantArrayType(Arg); if (!ConstantArrayArg) return Sema::TDK_NonDeducedMismatch; const ConstantArrayType *ConstantArrayParm = - Context.getAsConstantArrayType(Param); + S.Context.getAsConstantArrayType(Param); if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize()) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, ConstantArrayParm->getElementType(), ConstantArrayArg->getElementType(), Info, Deduced, 0); @@ -542,15 +542,15 @@ DeduceTemplateArguments(ASTContext &Context, // type [i] case Type::DependentSizedArray: { - const ArrayType *ArrayArg = Context.getAsArrayType(Arg); + const ArrayType *ArrayArg = S.Context.getAsArrayType(Arg); if (!ArrayArg) return Sema::TDK_NonDeducedMismatch; // Check the element type of the arrays const DependentSizedArrayType *DependentArrayParm - = Context.getAsDependentSizedArrayType(Param); + = S.Context.getAsDependentSizedArrayType(Param); if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, + = DeduceTemplateArguments(S, TemplateParams, DependentArrayParm->getElementType(), ArrayArg->getElementType(), Info, Deduced, 0)) @@ -569,12 +569,12 @@ DeduceTemplateArguments(ASTContext &Context, if (const ConstantArrayType *ConstantArrayArg = dyn_cast<ConstantArrayType>(ArrayArg)) { llvm::APSInt Size(ConstantArrayArg->getSize()); - return DeduceNonTypeTemplateArgument(Context, NTTP, Size, + return DeduceNonTypeTemplateArgument(S, NTTP, Size, Info, Deduced); } if (const DependentSizedArrayType *DependentArrayArg = dyn_cast<DependentSizedArrayType>(ArrayArg)) - return DeduceNonTypeTemplateArgument(Context, NTTP, + return DeduceNonTypeTemplateArgument(S, NTTP, DependentArrayArg->getSizeExpr(), Info, Deduced); @@ -606,7 +606,7 @@ DeduceTemplateArguments(ASTContext &Context, // Check return types. if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, + = DeduceTemplateArguments(S, TemplateParams, FunctionProtoParam->getResultType(), FunctionProtoArg->getResultType(), Info, Deduced, 0)) @@ -615,7 +615,7 @@ DeduceTemplateArguments(ASTContext &Context, for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) { // Check argument types. if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, + = DeduceTemplateArguments(S, TemplateParams, FunctionProtoParam->getArgType(I), FunctionProtoArg->getArgType(I), Info, Deduced, 0)) @@ -636,7 +636,7 @@ DeduceTemplateArguments(ASTContext &Context, // Try to deduce template arguments from the template-id. Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, SpecParam, Arg, + = DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info, Deduced); if (Result && (TDF & TDF_DerivedClass)) { @@ -649,7 +649,13 @@ DeduceTemplateArguments(ASTContext &Context, // More importantly: // These alternatives are considered only if type deduction would // otherwise fail. - if (const RecordType *RecordT = dyn_cast<RecordType>(Arg)) { + if (const RecordType *RecordT = Arg->getAs<RecordType>()) { + // We cannot inspect base classes as part of deduction when the type + // is incomplete, so either instantiate any templates necessary to + // complete the type, or skip over it if it cannot be completed. + if (S.RequireCompleteType(Info.getLocation(), Arg, 0)) + return Result; + // Use data recursion to crawl through the list of base classes. // Visited contains the set of nodes we have already visited, while // ToVisit is our stack of records that we still need to visit. @@ -670,7 +676,7 @@ DeduceTemplateArguments(ASTContext &Context, // deduction from it. if (NextT != RecordT) { Sema::TemplateDeductionResult BaseResult - = DeduceTemplateArguments(Context, TemplateParams, SpecParam, + = DeduceTemplateArguments(S, TemplateParams, SpecParam, QualType(NextT, 0), Info, Deduced); // If template argument deduction for this base was successful, @@ -715,14 +721,14 @@ DeduceTemplateArguments(ASTContext &Context, return Sema::TDK_NonDeducedMismatch; if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, + = DeduceTemplateArguments(S, TemplateParams, MemPtrParam->getPointeeType(), MemPtrArg->getPointeeType(), Info, Deduced, TDF & TDF_IgnoreQualifiers)) return Result; - return DeduceTemplateArguments(Context, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, QualType(MemPtrParam->getClass(), 0), QualType(MemPtrArg->getClass(), 0), Info, Deduced, 0); @@ -740,7 +746,7 @@ DeduceTemplateArguments(ASTContext &Context, if (!BlockPtrArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArguments(Context, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, BlockPtrParam->getPointeeType(), BlockPtrArg->getPointeeType(), Info, Deduced, 0); @@ -761,7 +767,7 @@ DeduceTemplateArguments(ASTContext &Context, } static Sema::TemplateDeductionResult -DeduceTemplateArguments(ASTContext &Context, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument &Param, const TemplateArgument &Arg, @@ -774,7 +780,7 @@ DeduceTemplateArguments(ASTContext &Context, case TemplateArgument::Type: if (Arg.getKind() == TemplateArgument::Type) - return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(), + return DeduceTemplateArguments(S, TemplateParams, Param.getAsType(), Arg.getAsType(), Info, Deduced, 0); Info.FirstArg = Param; Info.SecondArg = Arg; @@ -782,7 +788,7 @@ DeduceTemplateArguments(ASTContext &Context, case TemplateArgument::Template: if (Arg.getKind() == TemplateArgument::Template) - return DeduceTemplateArguments(Context, TemplateParams, + return DeduceTemplateArguments(S, TemplateParams, Param.getAsTemplate(), Arg.getAsTemplate(), Info, Deduced); Info.FirstArg = Param; @@ -826,14 +832,14 @@ DeduceTemplateArguments(ASTContext &Context, = getDeducedParameterFromExpr(Param.getAsExpr())) { if (Arg.getKind() == TemplateArgument::Integral) // FIXME: Sign problems here - return DeduceNonTypeTemplateArgument(Context, NTTP, + return DeduceNonTypeTemplateArgument(S, NTTP, *Arg.getAsIntegral(), Info, Deduced); if (Arg.getKind() == TemplateArgument::Expression) - return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(), + return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(), Info, Deduced); if (Arg.getKind() == TemplateArgument::Declaration) - return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsDecl(), + return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsDecl(), Info, Deduced); assert(false && "Type/value mismatch"); @@ -854,7 +860,7 @@ DeduceTemplateArguments(ASTContext &Context, } static Sema::TemplateDeductionResult -DeduceTemplateArguments(ASTContext &Context, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgumentList &ParamList, const TemplateArgumentList &ArgList, @@ -863,7 +869,7 @@ DeduceTemplateArguments(ASTContext &Context, assert(ParamList.size() == ArgList.size()); for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, TemplateParams, + = DeduceTemplateArguments(S, TemplateParams, ParamList[I], ArgList[I], Info, Deduced)) return Result; @@ -951,7 +957,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, llvm::SmallVector<TemplateArgument, 4> Deduced; Deduced.resize(Partial->getTemplateParameters()->size()); if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(Context, + = ::DeduceTemplateArguments(*this, Partial->getTemplateParameters(), Partial->getTemplateArgs(), TemplateArgs, Info, Deduced)) @@ -1306,6 +1312,91 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, return TDK_Success; } +static QualType GetTypeOfFunction(ASTContext &Context, + bool isAddressOfOperand, + FunctionDecl *Fn) { + if (!isAddressOfOperand) return Fn->getType(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) + if (Method->isInstance()) + return Context.getMemberPointerType(Fn->getType(), + Context.getTypeDeclType(Method->getParent()).getTypePtr()); + return Context.getPointerType(Fn->getType()); +} + +/// Apply the deduction rules for overload sets. +/// +/// \return the null type if this argument should be treated as an +/// undeduced context +static QualType +ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, + Expr *Arg, QualType ParamType) { + llvm::PointerIntPair<OverloadExpr*,1> R = OverloadExpr::find(Arg); + + bool isAddressOfOperand = bool(R.getInt()); + OverloadExpr *Ovl = R.getPointer(); + + // If there were explicit template arguments, we can only find + // something via C++ [temp.arg.explicit]p3, i.e. if the arguments + // unambiguously name a full specialization. + if (Ovl->hasExplicitTemplateArgs()) { + // But we can still look for an explicit specialization. + if (FunctionDecl *ExplicitSpec + = S.ResolveSingleFunctionTemplateSpecialization(Ovl)) + return GetTypeOfFunction(S.Context, isAddressOfOperand, ExplicitSpec); + return QualType(); + } + + // C++0x [temp.deduct.call]p6: + // When P is a function type, pointer to function type, or pointer + // to member function type: + + if (!ParamType->isFunctionType() && + !ParamType->isFunctionPointerType() && + !ParamType->isMemberFunctionPointerType()) + return QualType(); + + QualType Match; + for (UnresolvedSetIterator I = Ovl->decls_begin(), + E = Ovl->decls_end(); I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + + // - If the argument is an overload set containing one or more + // function templates, the parameter is treated as a + // non-deduced context. + if (isa<FunctionTemplateDecl>(D)) + return QualType(); + + FunctionDecl *Fn = cast<FunctionDecl>(D); + QualType ArgType = GetTypeOfFunction(S.Context, isAddressOfOperand, Fn); + + // - If the argument is an overload set (not containing function + // templates), trial argument deduction is attempted using each + // of the members of the set. If deduction succeeds for only one + // of the overload set members, that member is used as the + // argument value for the deduction. If deduction succeeds for + // more than one member of the overload set the parameter is + // treated as a non-deduced context. + + // We do all of this in a fresh context per C++0x [temp.deduct.type]p2: + // 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()); + Sema::TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); + unsigned TDF = 0; + + Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, + ParamType, ArgType, + Info, Deduced, TDF); + if (Result) continue; + if (!Match.isNull()) return QualType(); + Match = ArgType; + } + + return Match; +} + /// \brief Perform template argument deduction from a function call /// (C++ [temp.deduct.call]). /// @@ -1384,6 +1475,15 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ParamType = ParamTypes[I]; QualType ArgType = Args[I]->getType(); + // Overload sets usually make this parameter an undeduced + // context, but there are sometimes special circumstances. + if (ArgType == Context.OverloadTy) { + ArgType = ResolveOverloadForDeduction(*this, TemplateParams, + Args[I], ParamType); + if (ArgType.isNull()) + continue; + } + // C++ [temp.deduct.call]p2: // If P is not a reference type: QualType CanonParamType = Context.getCanonicalType(ParamType); @@ -1454,38 +1554,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, ParamType->getAs<PointerType>()->getPointeeType()))) TDF |= TDF_DerivedClass; - // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function - // pointer parameters. - - if (Context.hasSameUnqualifiedType(ArgType, Context.OverloadTy)) { - // We know that template argument deduction will fail if the argument is - // still an overloaded function. Check whether we can resolve this - // argument as a single function template specialization per - // C++ [temp.arg.explicit]p3. - FunctionDecl *ExplicitSpec - = ResolveSingleFunctionTemplateSpecialization(Args[I]); - Expr *ResolvedArg = 0; - if (ExplicitSpec) - ResolvedArg = FixOverloadedFunctionReference(Args[I], ExplicitSpec); - if (!ExplicitSpec || !ResolvedArg) { - // Template argument deduction fails if we can't resolve the overloaded - // function. - return TDK_FailedOverloadResolution; - } - - // Get the type of the resolved argument, and adjust it per - // C++0x [temp.deduct.call]p3. - ArgType = ResolvedArg->getType(); - if (!ParamWasReference && ArgType->isFunctionType()) - ArgType = Context.getPointerType(ArgType); - if (ArgType->isPointerType() || ArgType->isMemberPointerType()) - TDF |= TDF_IgnoreQualifiers; - - ResolvedArg->Destroy(Context); - } - if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(Context, TemplateParams, + = ::DeduceTemplateArguments(*this, TemplateParams, ParamType, ArgType, Info, Deduced, TDF)) return Result; @@ -1548,11 +1618,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Trap any errors that might occur. SFINAETrap Trap(*this); + Deduced.resize(TemplateParams->size()); + if (!ArgFunctionType.isNull()) { // Deduce template arguments from the function type. - Deduced.resize(TemplateParams->size()); if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(Context, TemplateParams, + = ::DeduceTemplateArguments(*this, TemplateParams, FunctionType, ArgFunctionType, Info, Deduced, 0)) return Result; @@ -1651,7 +1722,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, (P->isMemberPointerType() && P->isMemberPointerType())) TDF |= TDF_IgnoreQualifiers; if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(Context, TemplateParams, + = ::DeduceTemplateArguments(*this, TemplateParams, P, A, Info, Deduced, TDF)) return Result; @@ -1702,7 +1773,7 @@ enum DeductionQualifierComparison { /// \brief Deduce the template arguments during partial ordering by comparing /// the parameter type and the argument type (C++0x [temp.deduct.partial]). /// -/// \param Context the AST context in which this deduction occurs. +/// \param S the semantic analysis object within which we are deducing /// /// \param TemplateParams the template parameters that we are deducing /// @@ -1718,14 +1789,14 @@ enum DeductionQualifierComparison { /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. static Sema::TemplateDeductionResult -DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context, +DeduceTemplateArgumentsDuringPartialOrdering(Sema &S, TemplateParameterList *TemplateParams, QualType ParamIn, QualType ArgIn, Sema::TemplateDeductionInfo &Info, llvm::SmallVectorImpl<TemplateArgument> &Deduced, llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) { - CanQualType Param = Context.getCanonicalType(ParamIn); - CanQualType Arg = Context.getCanonicalType(ArgIn); + CanQualType Param = S.Context.getCanonicalType(ParamIn); + CanQualType Arg = S.Context.getCanonicalType(ArgIn); // C++0x [temp.deduct.partial]p5: // Before the partial ordering is done, certain transformations are @@ -1772,7 +1843,7 @@ DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context, // described in 14.9.2.5. If deduction succeeds for a given type, the type // from the argument template is considered to be at least as specialized // as the type from the parameter template. - return DeduceTemplateArguments(Context, TemplateParams, Param, Arg, Info, + return DeduceTemplateArguments(S, TemplateParams, Param, Arg, Info, Deduced, TDF_None); } @@ -1785,6 +1856,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, /// \brief Determine whether the function template \p FT1 is at least as /// specialized as \p FT2. static bool isAtLeastAsSpecializedAs(Sema &S, + SourceLocation Loc, FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, @@ -1802,14 +1874,14 @@ static bool isAtLeastAsSpecializedAs(Sema &S, // C++0x [temp.deduct.partial]p3: // The types used to determine the ordering depend on the context in which // the partial ordering is done: - Sema::TemplateDeductionInfo Info(S.Context); + Sema::TemplateDeductionInfo Info(S.Context, Loc); switch (TPOC) { case TPOC_Call: { // - In the context of a function call, the function parameter types are // used. unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs()); for (unsigned I = 0; I != NumParams; ++I) - if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context, + if (DeduceTemplateArgumentsDuringPartialOrdering(S, TemplateParams, Proto2->getArgType(I), Proto1->getArgType(I), @@ -1824,7 +1896,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, case TPOC_Conversion: // - In the context of a call to a conversion operator, the return types // of the conversion function templates are used. - if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context, + if (DeduceTemplateArgumentsDuringPartialOrdering(S, TemplateParams, Proto2->getResultType(), Proto1->getResultType(), @@ -1837,7 +1909,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, case TPOC_Other: // - In other contexts (14.6.6.2) the function template’s function type // is used. - if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context, + if (DeduceTemplateArgumentsDuringPartialOrdering(S, TemplateParams, FD2->getType(), FD1->getType(), @@ -1916,10 +1988,11 @@ static bool isAtLeastAsSpecializedAs(Sema &S, FunctionTemplateDecl * Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, + SourceLocation Loc, TemplatePartialOrderingContext TPOC) { llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons; - bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, TPOC, 0); - bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, TPOC, + bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, 0); + bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, &QualifierComparisons); if (Better1 != Better2) // We have a clear winner @@ -1987,11 +2060,11 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// \brief Retrieve the most specialized of the given function template /// specializations. /// -/// \param Specializations the set of function template specializations that -/// we will be comparing. +/// \param SpecBegin the start iterator of the function template +/// specializations that we will be comparing. /// -/// \param NumSpecializations the number of function template specializations in -/// \p Specializations +/// \param SpecEnd the end iterator of the function template +/// specializations, paired with \p SpecBegin. /// /// \param TPOC the partial ordering context to use to compare the function /// template specializations. @@ -2015,42 +2088,38 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// specialization. /// /// \returns the most specialized function template specialization, if -/// found. Otherwise, returns NULL. +/// found. Otherwise, returns SpecEnd. /// /// \todo FIXME: Consider passing in the "also-ran" candidates that failed /// template argument deduction. -FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations, - unsigned NumSpecializations, - TemplatePartialOrderingContext TPOC, - SourceLocation Loc, - const PartialDiagnostic &NoneDiag, - const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag, - unsigned *Index) { - if (NumSpecializations == 0) { +UnresolvedSetIterator +Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, + UnresolvedSetIterator SpecEnd, + TemplatePartialOrderingContext TPOC, + SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag) { + if (SpecBegin == SpecEnd) { Diag(Loc, NoneDiag); - return 0; + return SpecEnd; } - if (NumSpecializations == 1) { - if (Index) - *Index = 0; - - return Specializations[0]; - } - + if (SpecBegin + 1 == SpecEnd) + return SpecBegin; // Find the function template that is better than all of the templates it // has been compared to. - unsigned Best = 0; + UnresolvedSetIterator Best = SpecBegin; FunctionTemplateDecl *BestTemplate - = Specializations[Best]->getPrimaryTemplate(); + = cast<FunctionDecl>(*Best)->getPrimaryTemplate(); assert(BestTemplate && "Not a function template specialization?"); - for (unsigned I = 1; I != NumSpecializations; ++I) { - FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate(); + for (UnresolvedSetIterator I = SpecBegin + 1; I != SpecEnd; ++I) { + FunctionTemplateDecl *Challenger + = cast<FunctionDecl>(*I)->getPrimaryTemplate(); assert(Challenger && "Not a function template specialization?"); - if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, - TPOC), + if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, + Loc, TPOC), Challenger)) { Best = I; BestTemplate = Challenger; @@ -2060,11 +2129,12 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations, // Make sure that the "best" function template is more specialized than all // of the others. bool Ambiguous = false; - for (unsigned I = 0; I != NumSpecializations; ++I) { - FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate(); + for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) { + FunctionTemplateDecl *Challenger + = cast<FunctionDecl>(*I)->getPrimaryTemplate(); if (I != Best && !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, - TPOC), + Loc, TPOC), BestTemplate)) { Ambiguous = true; break; @@ -2073,22 +2143,20 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations, if (!Ambiguous) { // We found an answer. Return it. - if (Index) - *Index = Best; - return Specializations[Best]; + return Best; } // Diagnose the ambiguity. Diag(Loc, AmbigDiag); // FIXME: Can we order the candidates in some sane way? - for (unsigned I = 0; I != NumSpecializations; ++I) - Diag(Specializations[I]->getLocation(), CandidateDiag) + for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) + Diag((*I)->getLocation(), CandidateDiag) << getTemplateArgumentBindingsText( - Specializations[I]->getPrimaryTemplate()->getTemplateParameters(), - *Specializations[I]->getTemplateSpecializationArgs()); + cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(), + *cast<FunctionDecl>(*I)->getTemplateSpecializationArgs()); - return 0; + return SpecEnd; } /// \brief Returns the more specialized class template partial specialization @@ -2104,7 +2172,8 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations, ClassTemplatePartialSpecializationDecl * Sema::getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, - ClassTemplatePartialSpecializationDecl *PS2) { + ClassTemplatePartialSpecializationDecl *PS2, + SourceLocation Loc) { // C++ [temp.class.order]p1: // For two class template partial specializations, the first is at least as // specialized as the second if, given the following rewrite to two @@ -2127,11 +2196,11 @@ Sema::getMoreSpecializedPartialSpecialization( // template partial ordering, because class template partial specializations // are more constrained. We know that every template parameter is deduc llvm::SmallVector<TemplateArgument, 4> Deduced; - Sema::TemplateDeductionInfo Info(Context); + Sema::TemplateDeductionInfo Info(Context, Loc); // Determine whether PS1 is at least as specialized as PS2 Deduced.resize(PS2->getTemplateParameters()->size()); - bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(Context, + bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, PS2->getTemplateParameters(), Context.getTypeDeclType(PS2), Context.getTypeDeclType(PS1), @@ -2142,7 +2211,7 @@ Sema::getMoreSpecializedPartialSpecialization( // Determine whether PS2 is at least as specialized as PS1 Deduced.clear(); Deduced.resize(PS1->getTemplateParameters()->size()); - bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(Context, + bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, PS1->getTemplateParameters(), Context.getTypeDeclType(PS1), Context.getTypeDeclType(PS2), diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 2db0deb5098b..51e17fe472e5 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -33,9 +33,15 @@ using namespace clang; /// arguments. /// /// \param Innermost if non-NULL, the innermost template argument list. +/// +/// \param RelativeToPrimary true if we should get the template +/// arguments relative to the primary template, even when we're +/// dealing with a specialization. This is only relevant for function +/// template specializations. MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(NamedDecl *D, - const TemplateArgumentList *Innermost) { + const TemplateArgumentList *Innermost, + bool RelativeToPrimary) { // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; @@ -64,8 +70,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, } // Add template arguments from a function template specialization. else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) { - if (Function->getTemplateSpecializationKind() - == TSK_ExplicitSpecialization) + if (!RelativeToPrimary && + Function->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) break; if (const TemplateArgumentList *TemplateArgs @@ -86,11 +93,13 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, if (Function->getFriendObjectKind() && Function->getDeclContext()->isFileContext()) { Ctx = Function->getLexicalDeclContext(); + RelativeToPrimary = false; continue; } } Ctx = Ctx->getParent(); + RelativeToPrimary = false; } return Result; @@ -555,6 +564,8 @@ namespace { Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); + Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, + NonTypeTemplateParmDecl *D); /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. @@ -569,6 +580,14 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) { if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some + // arguments left unspecified. + if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(), + TTP->getPosition())) + return D; + TemplateName Template = TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate(); assert(!Template.isNull() && Template.getAsTemplateDecl() && @@ -576,14 +595,6 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) { return Template.getAsTemplateDecl(); } - // If the corresponding template argument is NULL or non-existent, it's - // because we are performing instantiation from explicitly-specified - // template arguments in a function template, but there were some - // arguments left unspecified. - if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(), - TTP->getPosition())) - return D; - // Fall through to find the instantiated declaration for this template // template parameter. } @@ -676,8 +687,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { PredefinedExpr::IdentType IT = E->getIdentType(); - unsigned Length = - PredefinedExpr::ComputeName(getSema().Context, IT, currentDecl).length(); + unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length(); llvm::APInt LengthI(32, Length + 1); QualType ResTy = getSema().Context.CharTy.withConst(); @@ -689,88 +699,145 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { } Sema::OwningExprResult -TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { - // FIXME: Clean this up a bit - NamedDecl *D = E->getDecl(); - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { - if (NTTP->getDepth() < TemplateArgs.getNumLevels()) { - // If the corresponding template argument is NULL or non-existent, it's - // because we are performing instantiation from explicitly-specified - // template arguments in a function template, but there were some - // arguments left unspecified. - if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), - NTTP->getPosition())) - return SemaRef.Owned(E->Retain()); +TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, + NonTypeTemplateParmDecl *NTTP) { + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some + // arguments left unspecified. + if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), + NTTP->getPosition())) + return SemaRef.Owned(E->Retain()); - const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), - NTTP->getPosition()); + const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), + NTTP->getPosition()); - // The template argument itself might be an expression, in which - // case we just return that expression. - if (Arg.getKind() == TemplateArgument::Expression) - return SemaRef.Owned(Arg.getAsExpr()->Retain()); + // The template argument itself might be an expression, in which + // case we just return that expression. + if (Arg.getKind() == TemplateArgument::Expression) + return SemaRef.Owned(Arg.getAsExpr()->Retain()); - if (Arg.getKind() == TemplateArgument::Declaration) { - ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); + if (Arg.getKind() == TemplateArgument::Declaration) { + ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); - VD = cast_or_null<ValueDecl>( + // Find the instantiation of the template argument. This is + // required for nested templates. + VD = cast_or_null<ValueDecl>( getSema().FindInstantiatedDecl(VD, TemplateArgs)); - if (!VD) + if (!VD) + return SemaRef.ExprError(); + + // Derive the type we want the substituted decl to have. This had + // better be non-dependent, or these checks will have serious problems. + QualType TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs, + E->getLocation(), + 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(); - if (VD->getDeclContext()->isRecord()) { - // 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 (NTTP->getType()->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(); - - return SemaRef.CreateBuiltinUnaryOp(E->getLocation(), - UnaryOperator::AddrOf, - move(RefExpr)); - } - } + RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(), + UnaryOperator::AddrOf, + move(RefExpr)); + assert(!RefExpr.isInvalid() && + SemaRef.Context.hasSameType(((Expr*) RefExpr.get())->getType(), + TargetType)); + return move(RefExpr); + } + } - return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), - E->getLocation()); + 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); } - assert(Arg.getKind() == TemplateArgument::Integral); - QualType T = Arg.getIntegralType(); - if (T->isCharType() || T->isWideCharType()) - return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( + // 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()); + } + + 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( + 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( + assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); + return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( *Arg.getAsIntegral(), T, E->getSourceRange().getBegin())); - } +} + + +Sema::OwningExprResult +TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { + NamedDecl *D = E->getDecl(); + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { + if (NTTP->getDepth() < TemplateArgs.getNumLevels()) + return TransformTemplateParmRefExpr(E, NTTP); // We have a non-type template parameter that isn't fully substituted; // FindInstantiatedDecl will find it in the local instantiation scope. @@ -986,7 +1053,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, bool Invalid = false; CXXRecordDecl *PatternDef - = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); + = cast_or_null<CXXRecordDecl>(Pattern->getDefinition()); if (!PatternDef) { if (!Complain) { // Say nothing @@ -1063,9 +1130,18 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // If this is a polymorphic C++ class without a key function, we'll // have to mark all of the virtual members to allow emission of a vtable // in this translation unit. - if (Instantiation->isDynamicClass() && !Context.getKeyFunction(Instantiation)) + if (Instantiation->isDynamicClass() && + !Context.getKeyFunction(Instantiation)) { + // Local classes need to have their methods instantiated immediately in + // order to have the correct instantiation scope. + if (Instantiation->isLocalClass()) { + MarkVirtualMembersReferenced(PointOfInstantiation, + Instantiation); + } else { ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation, PointOfInstantiation)); + } + } if (!Invalid) Consumer.HandleTagDeclDefinition(Instantiation); @@ -1124,7 +1200,7 @@ Sema::InstantiateClassTemplateSpecialization( PartialEnd = Template->getPartialSpecializations().end(); Partial != PartialEnd; ++Partial) { - TemplateDeductionInfo Info(Context); + TemplateDeductionInfo Info(Context, PointOfInstantiation); if (TemplateDeductionResult Result = DeduceTemplateArguments(&*Partial, ClassTemplateSpec->getTemplateArgs(), @@ -1154,7 +1230,8 @@ Sema::InstantiateClassTemplateSpecialization( for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1, PEnd = Matched.end(); P != PEnd; ++P) { - if (getMoreSpecializedPartialSpecialization(P->first, Best->first) + if (getMoreSpecializedPartialSpecialization(P->first, Best->first, + PointOfInstantiation) == P->first) Best = P; } @@ -1166,7 +1243,8 @@ Sema::InstantiateClassTemplateSpecialization( PEnd = Matched.end(); P != PEnd; ++P) { if (P != Best && - getMoreSpecializedPartialSpecialization(P->first, Best->first) + getMoreSpecializedPartialSpecialization(P->first, Best->first, + PointOfInstantiation) != Best->first) { Ambiguous = true; break; @@ -1327,8 +1405,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); assert(Pattern && "Missing instantiated-from-template information"); - if (!Record->getDefinition(Context)) { - if (!Pattern->getDefinition(Context)) { + if (!Record->getDefinition()) { + if (!Pattern->getDefinition()) { // C++0x [temp.explicit]p8: // An explicit instantiation definition that names a class template // specialization explicitly instantiates the class template @@ -1348,7 +1426,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, TSK); } - Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context)); + Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition()); if (Pattern) InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs, TSK); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 23a9430d746f..0b0efcb83327 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -43,6 +43,7 @@ namespace { // clang/AST/DeclNodes.def. Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); + Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D); Decl *VisitTypedefDecl(TypedefDecl *D); Decl *VisitVarDecl(VarDecl *D); Decl *VisitFieldDecl(FieldDecl *D); @@ -126,6 +127,21 @@ TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { return D; } +Decl * +TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + NamespaceAliasDecl *Inst + = NamespaceAliasDecl::Create(SemaRef.Context, Owner, + D->getNamespaceLoc(), + D->getAliasLoc(), + D->getNamespace()->getIdentifier(), + D->getQualifierRange(), + D->getQualifier(), + D->getTargetNameLoc(), + D->getNamespace()); + Owner->addDecl(Inst); + return Inst; +} + Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); @@ -217,6 +233,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // FIXME: having to fake up a LookupResult is dumb. LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(), Sema::LookupOrdinaryName); + if (D->isStaticDataMember()) + SemaRef.LookupQualifiedName(Previous, Owner, false); SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration); if (D->isOutOfLine()) { @@ -232,7 +250,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, TSK_ImplicitInstantiation); - if (D->getInit()) { + if (Var->getAnyInitializer()) { + // We already have an initializer in the class. + } else if (D->getInit()) { if (Var->isStaticDataMember() && !D->isOutOfLine()) SemaRef.PushExpressionEvaluationContext(Sema::Unevaluated); else @@ -241,6 +261,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Extract the initializer, skipping through any temporary-binding // expressions and look at the subexpression as it was written. Expr *DInit = D->getInit(); + if (CXXExprWithTemporaries *ExprTemp + = dyn_cast<CXXExprWithTemporaries>(DInit)) + DInit = ExprTemp->getSubExpr(); while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(DInit)) DInit = Binder->getSubExpr(); if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(DInit)) @@ -408,9 +431,17 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { Decl *NewND; // Hack to make this work almost well pending a rewrite. - if (ND->getDeclContext()->isRecord()) - NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs); - else if (D->wasSpecialization()) { + if (ND->getDeclContext()->isRecord()) { + if (!ND->getDeclContext()->isDependentContext()) { + NewND = SemaRef.FindInstantiatedDecl(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()) { // Totally egregious hack to work around PR5866 return 0; } else @@ -493,6 +524,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { } if (EnumConst) { + EnumConst->setAccess(Enum->getAccess()); Enum->addDecl(EnumConst); Enumerators.push_back(Sema::DeclPtrTy::make(EnumConst)); LastEnumConst = EnumConst; @@ -734,9 +766,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, if (T.isNull()) return 0; - // Build the instantiated method declaration. - DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext(), - TemplateArgs); + // 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 + DC = SemaRef.FindInstantiatedContext(D->getDeclContext(), TemplateArgs); + FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), D->getDeclName(), T, D->getTypeSourceInfo(), @@ -747,7 +784,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) Params[P]->setOwningFunction(Function); - Function->setParams(SemaRef.Context, Params.data(), Params.size()); + Function->setParams(Params.data(), Params.size()); if (TemplateParams) { // Our resulting instantiation is actually a function template, since we @@ -772,8 +809,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); } else if (FunctionTemplate) { // Record this function template specialization. - Function->setFunctionTemplateSpecialization(SemaRef.Context, - FunctionTemplate, + Function->setFunctionTemplateSpecialization(FunctionTemplate, &TemplateArgs.getInnermost(), InsertPos); } @@ -926,8 +962,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (FunctionTemplate) { // Record this function template specialization. - Method->setFunctionTemplateSpecialization(SemaRef.Context, - FunctionTemplate, + Method->setFunctionTemplateSpecialization(FunctionTemplate, &TemplateArgs.getInnermost(), InsertPos); } else { @@ -944,7 +979,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) Params[P]->setOwningFunction(Method); - Method->setParams(SemaRef.Context, Params.data(), Params.size()); + Method->setParams(Params.data(), Params.size()); if (InitMethodInstantiation(Method, D)) Method->setInvalidDecl(); @@ -1804,7 +1839,6 @@ void Sema::InstantiateStaticDataMemberDefinition( CurContext = PreviousContext; if (Var) { - Var->setPreviousDeclaration(OldVar); MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo(); assert(MSInfo && "Missing member specialization information?"); Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(), @@ -1829,7 +1863,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, const MultiLevelTemplateArgumentList &TemplateArgs) { llvm::SmallVector<MemInitTy*, 4> NewInits; - + bool AnyErrors = false; + // Instantiate all the initializers. for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(), InitsEnd = Tmpl->init_end(); @@ -1837,26 +1872,38 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, CXXBaseOrMemberInitializer *Init = *Inits; ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this); + llvm::SmallVector<SourceLocation, 4> CommaLocs; // Instantiate all the arguments. - for (ExprIterator Args = Init->arg_begin(), ArgsEnd = Init->arg_end(); - Args != ArgsEnd; ++Args) { - OwningExprResult NewArg = SubstExpr(*Args, TemplateArgs); - - if (NewArg.isInvalid()) - New->setInvalidDecl(); - else - NewArgs.push_back(NewArg.takeAs<Expr>()); + Expr *InitE = Init->getInit(); + if (!InitE) { + // Nothing to instantiate; + } else if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(InitE)) { + if (InstantiateInitializationArguments(*this, ParenList->getExprs(), + ParenList->getNumExprs(), + TemplateArgs, CommaLocs, + NewArgs)) { + AnyErrors = true; + continue; + } + } else { + OwningExprResult InitArg = SubstExpr(InitE, TemplateArgs); + if (InitArg.isInvalid()) { + AnyErrors = true; + continue; + } + + NewArgs.push_back(InitArg.release()); } - + MemInitResult NewInit; - if (Init->isBaseInitializer()) { TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), TemplateArgs, Init->getSourceLocation(), New->getDeclName()); if (!BaseTInfo) { + AnyErrors = true; New->setInvalidDecl(); continue; } @@ -1884,9 +1931,10 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, Init->getRParenLoc()); } - if (NewInit.isInvalid()) + if (NewInit.isInvalid()) { + AnyErrors = true; New->setInvalidDecl(); - else { + } else { // FIXME: It would be nice if ASTOwningVector had a release function. NewArgs.take(); @@ -1898,7 +1946,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, ActOnMemInitializers(DeclPtrTy::make(New), /*FIXME: ColonLoc */ SourceLocation(), - NewInits.data(), NewInits.size()); + NewInits.data(), NewInits.size(), + AnyErrors); } // TODO: this could be templated if the various decl types used the @@ -2140,7 +2189,7 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs) { DeclContext *ParentDC = D->getDeclContext(); if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) || - isa<TemplateTypeParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || + isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) || ParentDC->isFunctionOrMethod()) { // D is a local of some kind. Look into the map of local // declarations to their instantiations. @@ -2151,10 +2200,11 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, if (!Record->isDependentContext()) return D; - // If the RecordDecl is actually the injected-class-name or a "templated" - // declaration for a class template or class template partial - // specialization, substitute into the injected-class-name of the - // class template or partial specialization to find the new DeclContext. + // If the RecordDecl is actually the injected-class-name or a + // "templated" declaration for a class template, class template + // partial specialization, or a member class of a class template, + // substitute into the injected-class-name of the class template + // or partial specialization to find the new DeclContext. QualType T; ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate(); @@ -2164,15 +2214,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) { T = Context.getTypeDeclType(Record); ClassTemplate = PartialSpec->getSpecializedTemplate(); - } + } if (!T.isNull()) { - // Substitute into the injected-class-name to get the type corresponding - // to the instantiation we want. This substitution should never fail, - // since we know we can instantiate the injected-class-name or we wouldn't - // have gotten to the injected-class-name! - // FIXME: Can we use the CurrentInstantiationScope to avoid this extra - // instantiation in the common case? + // Substitute into the injected-class-name to get the type + // corresponding to the instantiation we want, which may also be + // the current instantiation (if we're in a template + // definition). This substitution should never fail, since we + // know we can instantiate the injected-class-name or we + // wouldn't have gotten to the injected-class-name! + + // FIXME: Can we use the CurrentInstantiationScope to avoid this + // extra instantiation in the common case? T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName()); assert(!T.isNull() && "Instantiation of injected-class-name cannot fail."); @@ -2181,26 +2234,37 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, return T->getAs<RecordType>()->getDecl(); } - // We are performing "partial" template instantiation to create the - // member declarations for the members of a class template - // specialization. Therefore, D is actually referring to something in - // the current instantiation. Look through the current context, - // which contains actual instantiations, to find the instantiation of - // the "current instantiation" that D refers to. + // We are performing "partial" template instantiation to create + // the member declarations for the members of a class template + // specialization. Therefore, D is actually referring to something + // in the current instantiation. Look through the current + // context, which contains actual instantiations, to find the + // instantiation of the "current instantiation" that D refers + // to. + bool SawNonDependentContext = false; for (DeclContext *DC = CurContext; !DC->isFileContext(); DC = DC->getParent()) { if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(DC)) + = dyn_cast<ClassTemplateSpecializationDecl>(DC)) if (isInstantiationOf(ClassTemplate, Spec->getSpecializedTemplate())) return Spec; + + if (!DC->isDependentContext()) + SawNonDependentContext = true; } - assert(false && + // We're performing "instantiation" of a member of the current + // instantiation while we are type-checking the + // definition. Compute the declaration context and return that. + assert(!SawNonDependentContext && + "No dependent context while instantiating record"); + DeclContext *DC = computeDeclContext(T); + assert(DC && "Unable to find declaration for the current instantiation"); - return Record; + return cast<CXXRecordDecl>(DC); } - + // Fall through to deal with other dependent record types (e.g., // anonymous unions in class templates). } @@ -2275,6 +2339,24 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) { VarDecl *Var = cast<VarDecl>(Inst.first); assert(Var->isStaticDataMember() && "Not a static data member?"); + // Don't try to instantiate declarations if the most recent redeclaration + // is invalid. + if (Var->getMostRecentDeclaration()->isInvalidDecl()) + continue; + + // Check if the most recent declaration has changed the specialization kind + // and removed the need for implicit instantiation. + switch (Var->getMostRecentDeclaration()->getTemplateSpecializationKind()) { + case TSK_Undeclared: + assert(false && "Cannot instantitiate an undeclared specialization."); + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: + continue; // No longer need implicit instantiation. + case TSK_ImplicitInstantiation: + break; + } + PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Var), Var->getLocation(), *this, Context.getSourceManager(), diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 906576115a56..7911e76d446a 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -68,12 +68,41 @@ static bool isOmittedBlockReturnType(const Declarator &D) { return false; } +typedef std::pair<const AttributeList*,QualType> DelayedAttribute; +typedef llvm::SmallVectorImpl<DelayedAttribute> DelayedAttributeSet; + +static void ProcessTypeAttributeList(Sema &S, QualType &Type, + const AttributeList *Attrs, + DelayedAttributeSet &DelayedFnAttrs); +static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr); + +static void ProcessDelayedFnAttrs(Sema &S, QualType &Type, + DelayedAttributeSet &Attrs) { + for (DelayedAttributeSet::iterator I = Attrs.begin(), + E = Attrs.end(); I != E; ++I) + if (ProcessFnAttr(S, Type, *I->first)) + S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) + << I->first->getName() << I->second; + Attrs.clear(); +} + +static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) { + for (DelayedAttributeSet::iterator I = Attrs.begin(), + E = Attrs.end(); I != E; ++I) { + S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) + << I->first->getName() << I->second; + } + Attrs.clear(); +} + /// \brief Convert the specified declspec to the appropriate type /// object. /// \param D the declarator containing the declaration specifier. /// \returns The type described by the declaration specifiers. This function /// never returns null. -static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ +static QualType ConvertDeclSpecToType(Sema &TheSema, + Declarator &TheDeclarator, + DelayedAttributeSet &Delayed) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. const DeclSpec &DS = TheDeclarator.getDeclSpec(); @@ -343,6 +372,11 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ if (TheSema.getLangOptions().Freestanding) TheSema.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); Result = Context.getComplexType(Result); + } else if (DS.isTypeAltiVecVector()) { + unsigned typeSize = static_cast<unsigned>(Context.getTypeSize(Result)); + assert(typeSize > 0 && "type size for vector must be greater than 0 bits"); + Result = Context.getVectorType(Result, 128/typeSize, true, + DS.isTypeAltiVecPixel()); } assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary && @@ -351,7 +385,7 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ // See if there are any attributes on the declspec that apply to the type (as // opposed to the decl). if (const AttributeList *AL = DS.getAttributes()) - TheSema.ProcessTypeAttributeList(Result, AL); + ProcessTypeAttributeList(TheSema, Result, AL, Delayed); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -885,15 +919,23 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // have a type. QualType T; + llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec; + switch (D.getName().getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: - T = ConvertDeclSpecToType(D, *this); + T = ConvertDeclSpecToType(*this, D, FnAttrsFromDeclSpec); - if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned()) - *OwnedDecl = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep()); + if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { + TagDecl* Owned = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep()); + // Owned is embedded if it was defined here, or if it is the + // very first (i.e., canonical) declaration of this tag type. + Owned->setEmbeddedInDeclarator(Owned->isDefinition() || + Owned->isCanonicalDecl()); + if (OwnedDecl) *OwnedDecl = Owned; + } break; case UnqualifiedId::IK_ConstructorName: @@ -962,6 +1004,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.getIdentifier()) Name = D.getIdentifier(); + llvm::SmallVector<DelayedAttribute,4> FnAttrsFromPreviousChunk; + // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -1181,6 +1225,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, FTI.hasAnyExceptionSpec, Exceptions.size(), Exceptions.data()); } + + // For GCC compatibility, we allow attributes that apply only to + // function types to be placed on a function's return type + // instead (as long as that type doesn't happen to be function + // or function-pointer itself). + ProcessDelayedFnAttrs(*this, T, FnAttrsFromPreviousChunk); + break; } case DeclaratorChunk::MemberPointer: @@ -1239,9 +1290,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = Context.IntTy; } + DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk); + // See if there are any attributes on this declarator chunk. if (const AttributeList *AL = DeclType.getAttrs()) - ProcessTypeAttributeList(T, AL); + ProcessTypeAttributeList(*this, T, AL, FnAttrsFromPreviousChunk); } if (getLangOptions().CPlusPlus && T->isFunctionType()) { @@ -1271,10 +1324,18 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } - // If there were any type attributes applied to the decl itself (not the - // type, apply the type attribute to the type!) - if (const AttributeList *Attrs = D.getAttributes()) - ProcessTypeAttributeList(T, Attrs); + // Process any function attributes we might have delayed from the + // declaration-specifiers. + ProcessDelayedFnAttrs(*this, T, FnAttrsFromDeclSpec); + + // If there were any type attributes applied to the decl itself, not + // the type, apply them to the result type. But don't do this for + // block-literal expressions, which are parsed wierdly. + if (D.getContext() != Declarator::BlockLiteralContext) + if (const AttributeList *Attrs = D.getAttributes()) + ProcessTypeAttributeList(*this, T, Attrs, FnAttrsFromPreviousChunk); + + DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk); if (TInfo) { if (D.isInvalidType()) @@ -1645,20 +1706,79 @@ static void HandleObjCGCTypeAttribute(QualType &Type, Type = S.Context.getObjCGCQualType(Type, GCAttr); } -/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the -/// specified type. The attribute contains 0 arguments. -static void HandleNoReturnTypeAttribute(QualType &Type, - const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 0) - return; +/// Process an individual function attribute. Returns true if the +/// attribute does not make sense to apply to this type. +bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { + if (Attr.getKind() == AttributeList::AT_noreturn) { + // Complain immediately if the arg count is wrong. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return false; + } - // We only apply this to a pointer to function or a pointer to block. - if (!Type->isFunctionPointerType() - && !Type->isBlockPointerType() - && !Type->isFunctionType()) - return; + // Delay if this is not a function or pointer to block. + if (!Type->isFunctionPointerType() + && !Type->isBlockPointerType() + && !Type->isFunctionType()) + return true; - Type = S.Context.getNoReturnType(Type); + // Otherwise we can process right away. + Type = S.Context.getNoReturnType(Type); + return false; + } + + // Otherwise, a calling convention. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return false; + } + + QualType T = Type; + if (const PointerType *PT = Type->getAs<PointerType>()) + T = PT->getPointeeType(); + const FunctionType *Fn = T->getAs<FunctionType>(); + + // Delay if the type didn't work out to a function. + if (!Fn) return true; + + // TODO: diagnose uses of these conventions on the wrong target. + CallingConv CC; + switch (Attr.getKind()) { + case AttributeList::AT_cdecl: CC = CC_C; break; + case AttributeList::AT_fastcall: CC = CC_X86FastCall; break; + case AttributeList::AT_stdcall: CC = CC_X86StdCall; break; + default: llvm_unreachable("unexpected attribute kind"); return false; + } + + CallingConv CCOld = Fn->getCallConv(); + if (CC == CCOld) return false; + + if (CCOld != CC_Default) { + // Should we diagnose reapplications of the same convention? + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << FunctionType::getNameForCallConv(CC) + << FunctionType::getNameForCallConv(CCOld); + return false; + } + + // Diagnose the use of X86 fastcall on varargs or unprototyped functions. + if (CC == CC_X86FastCall) { + if (isa<FunctionNoProtoType>(Fn)) { + S.Diag(Attr.getLoc(), diag::err_cconv_knr) + << FunctionType::getNameForCallConv(CC); + return false; + } + + const FunctionProtoType *FnP = cast<FunctionProtoType>(Fn); + if (FnP->isVariadic()) { + S.Diag(Attr.getLoc(), diag::err_cconv_varargs) + << FunctionType::getNameForCallConv(CC); + return false; + } + } + + Type = S.Context.getCallConvType(Type, CC); + return false; } /// HandleVectorSizeAttribute - this attribute is only applicable to integral @@ -1705,10 +1825,12 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S // Success! Instantiate the vector type, the number of elements is > 0, and // not required to be a power of 2, unlike GCC. - CurType = S.Context.getVectorType(CurType, vectorSize/typeSize); + CurType = S.Context.getVectorType(CurType, vectorSize/typeSize, false, false); } -void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { +void ProcessTypeAttributeList(Sema &S, QualType &Result, + const AttributeList *AL, + DelayedAttributeSet &FnAttrs) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the // type, but others can be present in the type specifiers even though they @@ -1718,17 +1840,23 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { // the LeftOverAttrs list for rechaining. switch (AL->getKind()) { default: break; + case AttributeList::AT_address_space: - HandleAddressSpaceTypeAttribute(Result, *AL, *this); + HandleAddressSpaceTypeAttribute(Result, *AL, S); break; case AttributeList::AT_objc_gc: - HandleObjCGCTypeAttribute(Result, *AL, *this); - break; - case AttributeList::AT_noreturn: - HandleNoReturnTypeAttribute(Result, *AL, *this); + HandleObjCGCTypeAttribute(Result, *AL, S); break; case AttributeList::AT_vector_size: - HandleVectorSizeAttr(Result, *AL, *this); + HandleVectorSizeAttr(Result, *AL, S); + break; + + case AttributeList::AT_noreturn: + case AttributeList::AT_cdecl: + case AttributeList::AT_fastcall: + case AttributeList::AT_stdcall: + if (ProcessFnAttr(S, Result, *AL)) + FnAttrs.push_back(DelayedAttribute(AL, Result)); break; } } diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp index 7c19bf6e4fd4..d45d0106ffe6 100644 --- a/lib/Sema/TargetAttributesSema.cpp +++ b/lib/Sema/TargetAttributesSema.cpp @@ -70,6 +70,48 @@ namespace { }; } +static void HandleX86ForceAlignArgPointerAttr(Decl *D, + const AttributeList& Attr, + Sema &S) { + // Check the attribute arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + // If we try to apply it to a function pointer, warn. This is a special + // instance of the warn_attribute_ignored warning that can be turned + // off with -Wno-force-align-arg-pointer. + ValueDecl* VD = dyn_cast<ValueDecl>(D); + if (VD && VD->getType()->isFunctionPointerType()) { + S.Diag(Attr.getLoc(), diag::warn_faap_attribute_ignored); + return; + } + // Attribute can only be applied to function types. + if (!isa<FunctionDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << /* function */0; + return; + } + + D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr()); +} + +namespace { + class X86AttributesSema : public TargetAttributesSema { + public: + X86AttributesSema() { } + bool ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const { + if (Attr.getName()->getName() == "force_align_arg_pointer") { + HandleX86ForceAlignArgPointerAttr(D, Attr, S); + return true; + } + return false; + } + }; +} + const TargetAttributesSema &Sema::getTargetAttributesSema() const { if (TheTargetAttributesSema) return *TheTargetAttributesSema; @@ -81,6 +123,8 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const { case llvm::Triple::msp430: return *(TheTargetAttributesSema = new MSP430AttributesSema); + case llvm::Triple::x86: + return *(TheTargetAttributesSema = new X86AttributesSema); } } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index b2102afdfc42..fc069f7ba38a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -428,7 +428,8 @@ public: /// /// By default, performs semantic analysis when building the vector type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildVectorType(QualType ElementType, unsigned NumElements); + QualType RebuildVectorType(QualType ElementType, unsigned NumElements, + bool IsAltiVec, bool IsPixel); /// \brief Build a new extended vector type given the element type and /// number of elements. @@ -524,9 +525,13 @@ public: /// and the given type. Subclasses may override this routine to provide /// different behavior. QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) { - if (NNS->isDependent()) - return SemaRef.Context.getTypenameType(NNS, + if (NNS->isDependent()) { + CXXScopeSpec SS; + SS.setScopeRep(NNS); + if (!SemaRef.computeDeclContext(SS)) + return SemaRef.Context.getTypenameType(NNS, cast<TemplateSpecializationType>(T)); + } return SemaRef.Context.getQualifiedNameType(NNS, T); } @@ -776,6 +781,28 @@ public: StartLoc, EndLoc)); } + /// \brief Build a new inline asm statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildAsmStmt(SourceLocation AsmLoc, + bool IsSimple, + bool IsVolatile, + unsigned NumOutputs, + unsigned NumInputs, + IdentifierInfo **Names, + MultiExprArg Constraints, + MultiExprArg Exprs, + ExprArg AsmString, + MultiExprArg Clobbers, + SourceLocation RParenLoc, + bool MSAsm) { + return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, + NumInputs, Names, move(Constraints), + move(Exprs), move(AsmString), move(Clobbers), + RParenLoc, MSAsm); + } + /// \brief Build a new C++ exception declaration. /// /// By default, performs semantic analysis to build the new decaration. @@ -1662,6 +1689,7 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) { // Transform expressions by calling TransformExpr. #define STMT(Node, Parent) +#define ABSTRACT_EXPR(Node, Parent) #define EXPR(Node, Parent) case Stmt::Node##Class: #include "clang/AST/StmtNodes.def" { @@ -1685,6 +1713,7 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E) { switch (E->getStmtClass()) { case Stmt::NoStmtClass: break; #define STMT(Node, Parent) case Stmt::Node##Class: break; +#define ABSTRACT_EXPR(Node, Parent) #define EXPR(Node, Parent) \ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E)); #include "clang/AST/StmtNodes.def" @@ -2448,7 +2477,8 @@ QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType()) { - Result = getDerived().RebuildVectorType(ElementType, T->getNumElements()); + Result = getDerived().RebuildVectorType(ElementType, T->getNumElements(), + T->isAltiVec(), T->isPixel()); if (Result.isNull()) return QualType(); } @@ -3327,9 +3357,74 @@ TreeTransform<Derived>::TransformSwitchCase(SwitchCase *S) { template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { - // FIXME: Implement! - assert(false && "Inline assembly cannot be transformed"); - return SemaRef.Owned(S->Retain()); + + ASTOwningVector<&ActionBase::DeleteExpr> Constraints(getSema()); + ASTOwningVector<&ActionBase::DeleteExpr> Exprs(getSema()); + llvm::SmallVector<IdentifierInfo *, 4> Names; + + OwningExprResult AsmString(SemaRef); + ASTOwningVector<&ActionBase::DeleteExpr> Clobbers(getSema()); + + bool ExprsChanged = false; + + // Go through the outputs. + for (unsigned I = 0, E = S->getNumOutputs(); I != E; ++I) { + Names.push_back(S->getOutputIdentifier(I)); + + // No need to transform the constraint literal. + Constraints.push_back(S->getOutputConstraintLiteral(I)->Retain()); + + // Transform the output expr. + Expr *OutputExpr = S->getOutputExpr(I); + OwningExprResult Result = getDerived().TransformExpr(OutputExpr); + if (Result.isInvalid()) + return SemaRef.StmtError(); + + ExprsChanged |= Result.get() != OutputExpr; + + Exprs.push_back(Result.takeAs<Expr>()); + } + + // Go through the inputs. + for (unsigned I = 0, E = S->getNumInputs(); I != E; ++I) { + Names.push_back(S->getInputIdentifier(I)); + + // No need to transform the constraint literal. + Constraints.push_back(S->getInputConstraintLiteral(I)->Retain()); + + // Transform the input expr. + Expr *InputExpr = S->getInputExpr(I); + OwningExprResult Result = getDerived().TransformExpr(InputExpr); + if (Result.isInvalid()) + return SemaRef.StmtError(); + + ExprsChanged |= Result.get() != InputExpr; + + Exprs.push_back(Result.takeAs<Expr>()); + } + + if (!getDerived().AlwaysRebuild() && !ExprsChanged) + return SemaRef.Owned(S->Retain()); + + // Go through the clobbers. + for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I) + Clobbers.push_back(S->getClobber(I)->Retain()); + + // No need to transform the asm string literal. + AsmString = SemaRef.Owned(S->getAsmString()); + + return getDerived().RebuildAsmStmt(S->getAsmLoc(), + S->isSimple(), + S->isVolatile(), + S->getNumOutputs(), + S->getNumInputs(), + Names.data(), + move_arg(Constraints), + move_arg(Exprs), + move(AsmString), + move_arg(Clobbers), + S->getRParenLoc(), + S->isMSAsm()); } @@ -3742,13 +3837,6 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCastExpr(CastExpr *E) { - assert(false && "Cannot transform abstract class"); - return SemaRef.Owned(E->Retain()); -} - -template<typename Derived> -Sema::OwningExprResult TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) @@ -3812,13 +3900,6 @@ TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) { - assert(false && "Cannot transform abstract class"); - return SemaRef.Owned(E->Retain()); -} - -template<typename Derived> -Sema::OwningExprResult TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { TypeSourceInfo *OldT; TypeSourceInfo *NewT; @@ -4433,7 +4514,7 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { if (!Param) return SemaRef.ExprError(); - if (getDerived().AlwaysRebuild() && + if (!getDerived().AlwaysRebuild() && Param == E->getParam()) return SemaRef.Owned(E->Retain()); @@ -4733,6 +4814,12 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { + // CXXConstructExprs are always implicit, so when we have a + // 1-argument construction we just transform that argument. + if (E->getNumArgs() == 1 || + (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) + return getDerived().TransformExpr(E->getArg(0)); + TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4784,6 +4871,16 @@ TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { return getDerived().TransformExpr(E->getSubExpr()); } +/// \brief Transform a C++ reference-binding expression. +/// +/// Since CXXBindReferenceExpr nodes are implicitly generated, we just +/// transform the subexpression and return that. +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXBindReferenceExpr(CXXBindReferenceExpr *E) { + return getDerived().TransformExpr(E->getSubExpr()); +} + /// \brief Transform a C++ expression that contains temporaries that should /// be destroyed after the expression is evaluated. /// @@ -5330,9 +5427,11 @@ TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType, template<typename Derived> QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType, - unsigned NumElements) { + unsigned NumElements, + bool IsAltiVec, bool IsPixel) { // FIXME: semantic checking! - return SemaRef.Context.getVectorType(ElementType, NumElements); + return SemaRef.Context.getVectorType(ElementType, NumElements, + IsAltiVec, IsPixel); } template<typename Derived> @@ -5563,28 +5662,21 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // Compute the transformed set of functions (and function templates) to be // used during overload resolution. - Sema::FunctionSet Functions; + UnresolvedSet<16> Functions; if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(CalleeExpr)) { assert(ULE->requiresADL()); // FIXME: Do we have to check // IsAcceptableNonMemberOperatorCandidate for each of these? - for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), - E = ULE->decls_end(); I != E; ++I) - Functions.insert(AnyFunctionDecl::getFromNamedDecl(*I)); + Functions.append(ULE->decls_begin(), ULE->decls_end()); } else { - Functions.insert(AnyFunctionDecl::getFromNamedDecl( - cast<DeclRefExpr>(CalleeExpr)->getDecl())); + Functions.addDecl(cast<DeclRefExpr>(CalleeExpr)->getDecl()); } // Add any functions found via argument-dependent lookup. Expr *Args[2] = { FirstExpr, SecondExpr }; unsigned NumArgs = 1 + (SecondExpr != 0); - DeclarationName OpName - = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); - SemaRef.ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, - Functions); // Create the overloaded operator invocation for unary operators. if (NumArgs == 1 || isPostIncDec) { |