diff options
Diffstat (limited to 'lib')
98 files changed, 4737 insertions, 2714 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e028186d46e5..7f5fa35842af 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -40,7 +40,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, bool FreeMem, unsigned size_reserve) : GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), - sigjmp_bufDecl(0), SourceMgr(SM), LangOpts(LOpts), + sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), + SourceMgr(SM), LangOpts(LOpts), LoadedExternalComments(false), FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { @@ -554,10 +555,6 @@ ASTContext::getTypeInfo(const Type *T) { assert(false && "Should not see dependent types"); break; - case Type::ObjCProtocolList: - assert(false && "Should not see protocol list types"); - break; - case Type::FunctionNoProto: case Type::FunctionProto: // GCC extension: alignof(function) = 32 bits @@ -571,8 +568,6 @@ ASTContext::getTypeInfo(const Type *T) { Align = getTypeAlign(cast<ArrayType>(T)->getElementType()); break; - case Type::ConstantArrayWithExpr: - case Type::ConstantArrayWithoutExpr: case Type::ConstantArray: { const ConstantArrayType *CAT = cast<ConstantArrayType>(T); @@ -583,14 +578,16 @@ ASTContext::getTypeInfo(const Type *T) { } case Type::ExtVector: case Type::Vector: { - std::pair<uint64_t, unsigned> EltInfo = - getTypeInfo(cast<VectorType>(T)->getElementType()); - Width = EltInfo.first*cast<VectorType>(T)->getNumElements(); + const VectorType *VT = cast<VectorType>(T); + std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(VT->getElementType()); + Width = EltInfo.first*VT->getNumElements(); Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. // This happens for non-power-of-2 length vectors. - // FIXME: this should probably be a target property. - Align = 1 << llvm::Log2_32_Ceil(Align); + if (VT->getNumElements() & (VT->getNumElements()-1)) { + Align = llvm::NextPowerOf2(Align); + Width = llvm::RoundUpToAlignment(Width, Align); + } break; } @@ -749,9 +746,13 @@ ASTContext::getTypeInfo(const Type *T) { break; } - case Type::Elaborated: { - return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType().getTypePtr()); - } + case Type::SubstTemplateTypeParm: + return getTypeInfo(cast<SubstTemplateTypeParmType>(T)-> + getReplacementType().getTypePtr()); + + case Type::Elaborated: + return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType() + .getTypePtr()); case Type::Typedef: { const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl(); @@ -940,8 +941,14 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, /// \param T the type that will be the basis for type source info. This type /// should refer to how the declarator was written in source code, not to /// what type semantic analysis resolved the declarator to. -DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T) { - unsigned DataSize = TypeLoc::getFullDataSizeForType(T); +DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T, + unsigned DataSize) { + if (!DataSize) + DataSize = TypeLoc::getFullDataSizeForType(T); + else + assert(DataSize == TypeLoc::getFullDataSizeForType(T) && + "incorrect data size provided to CreateDeclaratorInfo!"); + DeclaratorInfo *DInfo = (DeclaratorInfo*)BumpAlloc.Allocate(sizeof(DeclaratorInfo) + DataSize, 8); new (DInfo) DeclaratorInfo(T); @@ -1140,7 +1147,7 @@ QualType ASTContext::getComplexType(QualType T) { // If the pointee type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { + if (!T.isCanonical()) { Canonical = getComplexType(getCanonicalType(T)); // Get the new insert position for the node we care about. @@ -1177,7 +1184,7 @@ QualType ASTContext::getPointerType(QualType T) { // If the pointee type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { + if (!T.isCanonical()) { Canonical = getPointerType(getCanonicalType(T)); // Get the new insert position for the node we care about. @@ -1207,7 +1214,7 @@ QualType ASTContext::getBlockPointerType(QualType T) { // If the block pointee type isn't canonical, this won't be a canonical // type either so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { + if (!T.isCanonical()) { Canonical = getBlockPointerType(getCanonicalType(T)); // Get the new insert position for the node we care about. @@ -1224,22 +1231,25 @@ QualType ASTContext::getBlockPointerType(QualType T) { /// getLValueReferenceType - Return the uniqued reference to the type for an /// lvalue reference to the specified type. -QualType ASTContext::getLValueReferenceType(QualType T) { +QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; - ReferenceType::Profile(ID, T); + ReferenceType::Profile(ID, T, SpelledAsLValue); void *InsertPos = 0; if (LValueReferenceType *RT = LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(RT, 0); + const ReferenceType *InnerRef = T->getAs<ReferenceType>(); + // If the referencee type isn't canonical, this won't be a canonical type // either, so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { - Canonical = getLValueReferenceType(getCanonicalType(T)); + if (!SpelledAsLValue || InnerRef || !T.isCanonical()) { + QualType PointeeType = (InnerRef ? InnerRef->getPointeeType() : T); + Canonical = getLValueReferenceType(getCanonicalType(PointeeType)); // Get the new insert position for the node we care about. LValueReferenceType *NewIP = @@ -1248,9 +1258,11 @@ QualType ASTContext::getLValueReferenceType(QualType T) { } LValueReferenceType *New - = new (*this, TypeAlignment) LValueReferenceType(T, Canonical); + = new (*this, TypeAlignment) LValueReferenceType(T, Canonical, + SpelledAsLValue); Types.push_back(New); LValueReferenceTypes.InsertNode(New, InsertPos); + return QualType(New, 0); } @@ -1260,18 +1272,21 @@ QualType ASTContext::getRValueReferenceType(QualType T) { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; - ReferenceType::Profile(ID, T); + ReferenceType::Profile(ID, T, false); void *InsertPos = 0; if (RValueReferenceType *RT = RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(RT, 0); + const ReferenceType *InnerRef = T->getAs<ReferenceType>(); + // If the referencee type isn't canonical, this won't be a canonical type // either, so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { - Canonical = getRValueReferenceType(getCanonicalType(T)); + if (InnerRef || !T.isCanonical()) { + QualType PointeeType = (InnerRef ? InnerRef->getPointeeType() : T); + Canonical = getRValueReferenceType(getCanonicalType(PointeeType)); // Get the new insert position for the node we care about. RValueReferenceType *NewIP = @@ -1302,7 +1317,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) { // If the pointee or class type isn't canonical, this won't be a canonical // type either, so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { + if (!T.isCanonical()) { Canonical = getMemberPointerType(getCanonicalType(T),getCanonicalType(Cls)); // Get the new insert position for the node we care about. @@ -1342,7 +1357,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, // 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 (!EltTy->isCanonical()) { + if (!EltTy.isCanonical()) { Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, ASM, EltTypeQuals); // Get the new insert position for the node we care about. @@ -1358,53 +1373,6 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, return QualType(New, 0); } -/// getConstantArrayWithExprType - Return a reference to the type for -/// an array of the specified element type. -QualType -ASTContext::getConstantArrayWithExprType(QualType EltTy, - const llvm::APInt &ArySizeIn, - Expr *ArySizeExpr, - ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, - SourceRange Brackets) { - // Convert the array size into a canonical width matching the pointer - // size for the target. - llvm::APInt ArySize(ArySizeIn); - ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); - - // Compute the canonical ConstantArrayType. - QualType Canonical = getConstantArrayType(getCanonicalType(EltTy), - ArySize, ASM, EltTypeQuals); - // Since we don't unique expressions, it isn't possible to unique VLA's - // that have an expression provided for their size. - ConstantArrayWithExprType *New = new(*this, TypeAlignment) - ConstantArrayWithExprType(EltTy, Canonical, ArySize, ArySizeExpr, - ASM, EltTypeQuals, Brackets); - Types.push_back(New); - return QualType(New, 0); -} - -/// getConstantArrayWithoutExprType - Return a reference to the type for -/// an array of the specified element type. -QualType -ASTContext::getConstantArrayWithoutExprType(QualType EltTy, - const llvm::APInt &ArySizeIn, - ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { - // Convert the array size into a canonical width matching the pointer - // size for the target. - llvm::APInt ArySize(ArySizeIn); - ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); - - // Compute the canonical ConstantArrayType. - QualType Canonical = getConstantArrayType(getCanonicalType(EltTy), - ArySize, ASM, EltTypeQuals); - ConstantArrayWithoutExprType *New = new(*this, TypeAlignment) - ConstantArrayWithoutExprType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); - Types.push_back(New); - return QualType(New, 0); -} - /// getVariableArrayType - Returns a non-unique reference to the type for a /// variable array of the specified element type. QualType ASTContext::getVariableArrayType(QualType EltTy, @@ -1484,7 +1452,7 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, // either, so fill in the canonical type field. QualType Canonical; - if (!EltTy->isCanonical()) { + if (!EltTy.isCanonical()) { Canonical = getIncompleteArrayType(getCanonicalType(EltTy), ASM, EltTypeQuals); @@ -1520,7 +1488,7 @@ 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()) { + if (!vecType.isCanonical()) { Canonical = getVectorType(getCanonicalType(vecType), NumElts); // Get the new insert position for the node we care about. @@ -1552,7 +1520,7 @@ QualType ASTContext::getExtVectorType(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()) { + if (!vecType.isCanonical()) { Canonical = getExtVectorType(getCanonicalType(vecType), NumElts); // Get the new insert position for the node we care about. @@ -1616,7 +1584,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) { return QualType(FT, 0); QualType Canonical; - if (!ResultTy->isCanonical()) { + if (!ResultTy.isCanonical()) { Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn); // Get the new insert position for the node we care about. @@ -1639,12 +1607,6 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, unsigned TypeQuals, bool hasExceptionSpec, bool hasAnyExceptionSpec, unsigned NumExs, const QualType *ExArray, bool NoReturn) { - if (LangOpts.CPlusPlus) { - for (unsigned i = 0; i != NumArgs; ++i) - assert(!ArgArray[i].hasQualifiers() && - "C++ arguments can't have toplevel qualifiers!"); - } - // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1658,11 +1620,9 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, return QualType(FTP, 0); // Determine whether the type being created is already canonical or not. - bool isCanonical = ResultTy->isCanonical(); - if (hasExceptionSpec) - isCanonical = false; + bool isCanonical = !hasExceptionSpec && ResultTy.isCanonical(); for (unsigned i = 0; i != NumArgs && isCanonical; ++i) - if (!ArgArray[i]->isCanonical()) + if (!ArgArray[i].isCanonicalAsParam()) isCanonical = false; // If this type isn't canonical, get the canonical version of it. @@ -1672,7 +1632,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, llvm::SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) - CanonicalArgs.push_back(getCanonicalType(ArgArray[i])); + CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i])); Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, @@ -1743,6 +1703,29 @@ QualType ASTContext::getTypedefType(TypedefDecl *Decl) { return QualType(Decl->TypeForDecl, 0); } +/// \brief Retrieve a substitution-result type. +QualType +ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, + QualType Replacement) { + assert(Replacement.isCanonical() + && "replacement types must always be canonical"); + + llvm::FoldingSetNodeID ID; + SubstTemplateTypeParmType::Profile(ID, Parm, Replacement); + void *InsertPos = 0; + SubstTemplateTypeParmType *SubstParm + = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (!SubstParm) { + SubstParm = new (*this, TypeAlignment) + SubstTemplateTypeParmType(Parm, Replacement); + Types.push_back(SubstParm); + SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); + } + + return QualType(SubstParm, 0); +} + /// \brief Retrieve the template type parameter type for a template /// parameter or parameter pack with the given depth, index, and (optionally) /// name. @@ -1933,7 +1916,17 @@ static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, return LHS->getDeclName() < RHS->getDeclName(); } -static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, +static bool areSortedAndUniqued(ObjCProtocolDecl **Protocols, + unsigned NumProtocols) { + if (NumProtocols == 0) return true; + + for (unsigned i = 1; i != NumProtocols; ++i) + if (!CmpProtocolNames(Protocols[i-1], Protocols[i])) + return false; + return true; +} + +static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols, unsigned &NumProtocols) { ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols; @@ -1950,10 +1943,6 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, ObjCProtocolDecl **Protocols, unsigned NumProtocols) { - // Sort the protocol list alphabetically to canonicalize it. - if (NumProtocols) - SortAndUniqueProtocols(Protocols, NumProtocols); - llvm::FoldingSetNodeID ID; ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols); @@ -1962,9 +1951,31 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); + // Sort the protocol list alphabetically to canonicalize it. + QualType Canonical; + if (!InterfaceT.isCanonical() || + !areSortedAndUniqued(Protocols, NumProtocols)) { + if (!areSortedAndUniqued(Protocols, NumProtocols)) { + llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols); + unsigned UniqueCount = NumProtocols; + + std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); + SortAndUniqueProtocols(&Sorted[0], UniqueCount); + + Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT), + &Sorted[0], UniqueCount); + } else { + Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT), + Protocols, NumProtocols); + } + + // Regenerate InsertPos. + ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos); + } + // No Match; ObjCObjectPointerType *QType = new (*this, TypeAlignment) - ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols); + ObjCObjectPointerType(Canonical, InterfaceT, Protocols, NumProtocols); Types.push_back(QType); ObjCObjectPointerTypes.InsertNode(QType, InsertPos); @@ -1975,10 +1986,6 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, /// specified ObjC interface decl. The list of protocols is optional. QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCProtocolDecl **Protocols, unsigned NumProtocols) { - if (NumProtocols) - // Sort the protocol list alphabetically to canonicalize it. - SortAndUniqueProtocols(Protocols, NumProtocols); - llvm::FoldingSetNodeID ID; ObjCInterfaceType::Profile(ID, Decl, Protocols, NumProtocols); @@ -1987,31 +1994,26 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); - // No Match; - ObjCInterfaceType *QType = new (*this, TypeAlignment) - ObjCInterfaceType(const_cast<ObjCInterfaceDecl*>(Decl), - Protocols, NumProtocols); - Types.push_back(QType); - ObjCInterfaceTypes.InsertNode(QType, InsertPos); - return QualType(QType, 0); -} + // Sort the protocol list alphabetically to canonicalize it. + QualType Canonical; + if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) { + llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols); + std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); -QualType ASTContext::getObjCProtocolListType(QualType T, - ObjCProtocolDecl **Protocols, - unsigned NumProtocols) { - llvm::FoldingSetNodeID ID; - ObjCProtocolListType::Profile(ID, T, Protocols, NumProtocols); + unsigned UniqueCount = NumProtocols; + SortAndUniqueProtocols(&Sorted[0], UniqueCount); - void *InsertPos = 0; - if (ObjCProtocolListType *QT = - ObjCProtocolListTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(QT, 0); + Canonical = getObjCInterfaceType(Decl, &Sorted[0], UniqueCount); + + ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + ObjCInterfaceType *QType = new (*this, TypeAlignment) + ObjCInterfaceType(Canonical, const_cast<ObjCInterfaceDecl*>(Decl), + Protocols, NumProtocols); - // No Match; - ObjCProtocolListType *QType = new (*this, TypeAlignment) - ObjCProtocolListType(T, Protocols, NumProtocols); Types.push_back(QType); - ObjCProtocolListTypes.InsertNode(QType, InsertPos); + ObjCInterfaceTypes.InsertNode(QType, InsertPos); return QualType(QType, 0); } @@ -2168,6 +2170,24 @@ QualType ASTContext::getPointerDiffType() const { // Type Operators //===----------------------------------------------------------------------===// +CanQualType ASTContext::getCanonicalParamType(QualType T) { + // Push qualifiers into arrays, and then discard any remaining + // qualifiers. + T = getCanonicalType(T); + const Type *Ty = T.getTypePtr(); + + QualType Result; + if (isa<ArrayType>(Ty)) { + Result = getArrayDecayedType(QualType(Ty,0)); + } else if (isa<FunctionType>(Ty)) { + Result = getPointerType(QualType(Ty, 0)); + } else { + Result = QualType(Ty, 0); + } + + return CanQualType::CreateUnsafe(Result); +} + /// getCanonicalType - Return the canonical (structural) type corresponding to /// the specified potentially non-canonical type. The non-canonical version /// of a type may have many "decorated" versions of types. Decorators can @@ -2512,7 +2532,7 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { /// routine will assert if passed a built-in type that isn't an integer or enum, /// or if it is not canonicalized. unsigned ASTContext::getIntegerRank(Type *T) { - assert(T->isCanonical() && "T should be canonicalized"); + assert(T->isCanonicalUnqualified() && "T should be canonicalized"); if (EnumType* ET = dyn_cast<EnumType>(T)) T = ET->getDecl()->getIntegerType().getTypePtr(); @@ -2713,6 +2733,226 @@ QualType ASTContext::getObjCFastEnumerationStateType() { return getTagDeclType(ObjCFastEnumerationStateTypeDecl); } +QualType ASTContext::getBlockDescriptorType() { + if (BlockDescriptorType) + return getTagDeclType(BlockDescriptorType); + + RecordDecl *T; + // FIXME: Needs the FlagAppleBlock bit. + T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__block_descriptor")); + + QualType FieldTypes[] = { + UnsignedLongTy, + UnsignedLongTy, + }; + + const char *FieldNames[] = { + "reserved", + "Size" + }; + + for (size_t i = 0; i < 2; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, + T, + SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false); + T->addDecl(Field); + } + + T->completeDefinition(*this); + + BlockDescriptorType = T; + + return getTagDeclType(BlockDescriptorType); +} + +void ASTContext::setBlockDescriptorType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + assert(Rec && "Invalid BlockDescriptorType"); + BlockDescriptorType = Rec->getDecl(); +} + +QualType ASTContext::getBlockDescriptorExtendedType() { + if (BlockDescriptorExtendedType) + return getTagDeclType(BlockDescriptorExtendedType); + + RecordDecl *T; + // FIXME: Needs the FlagAppleBlock bit. + T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__block_descriptor_withcopydispose")); + + QualType FieldTypes[] = { + UnsignedLongTy, + UnsignedLongTy, + getPointerType(VoidPtrTy), + getPointerType(VoidPtrTy) + }; + + const char *FieldNames[] = { + "reserved", + "Size", + "CopyFuncPtr", + "DestroyFuncPtr" + }; + + for (size_t i = 0; i < 4; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, + T, + SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false); + T->addDecl(Field); + } + + T->completeDefinition(*this); + + BlockDescriptorExtendedType = T; + + return getTagDeclType(BlockDescriptorExtendedType); +} + +void ASTContext::setBlockDescriptorExtendedType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + assert(Rec && "Invalid BlockDescriptorType"); + BlockDescriptorExtendedType = Rec->getDecl(); +} + +bool ASTContext::BlockRequiresCopying(QualType Ty) { + if (Ty->isBlockPointerType()) + return true; + if (isObjCNSObjectType(Ty)) + return true; + if (Ty->isObjCObjectPointerType()) + return true; + return false; +} + +QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { + // type = struct __Block_byref_1_X { + // void *__isa; + // struct __Block_byref_1_X *__forwarding; + // unsigned int __flags; + // unsigned int __size; + // void *__copy_helper; // as needed + // void *__destroy_help // as needed + // int X; + // } * + + bool HasCopyAndDispose = BlockRequiresCopying(Ty); + + // FIXME: Move up + static int UniqueBlockByRefTypeID = 0; + char Name[36]; + sprintf(Name, "__Block_byref_%d_%s", ++UniqueBlockByRefTypeID, DeclName); + RecordDecl *T; + T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get(Name)); + T->startDefinition(); + QualType Int32Ty = IntTy; + assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported"); + QualType FieldTypes[] = { + getPointerType(VoidPtrTy), + getPointerType(getTagDeclType(T)), + Int32Ty, + Int32Ty, + getPointerType(VoidPtrTy), + getPointerType(VoidPtrTy), + Ty + }; + + const char *FieldNames[] = { + "__isa", + "__forwarding", + "__flags", + "__size", + "__copy_helper", + "__destroy_helper", + DeclName, + }; + + for (size_t i = 0; i < 7; ++i) { + if (!HasCopyAndDispose && i >=4 && i <= 5) + continue; + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); + T->addDecl(Field); + } + + T->completeDefinition(*this); + + return getPointerType(getTagDeclType(T)); +} + + +QualType ASTContext::getBlockParmType( + bool BlockHasCopyDispose, + llvm::SmallVector<const Expr *, 8> &BlockDeclRefDecls) { + // FIXME: Move up + static int UniqueBlockParmTypeID = 0; + char Name[36]; + sprintf(Name, "__block_literal_%u", ++UniqueBlockParmTypeID); + RecordDecl *T; + T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get(Name)); + QualType FieldTypes[] = { + getPointerType(VoidPtrTy), + IntTy, + IntTy, + getPointerType(VoidPtrTy), + (BlockHasCopyDispose ? + getPointerType(getBlockDescriptorExtendedType()) : + getPointerType(getBlockDescriptorType())) + }; + + const char *FieldNames[] = { + "__isa", + "__flags", + "__reserved", + "__FuncPtr", + "__descriptor" + }; + + for (size_t i = 0; i < 5; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); + T->addDecl(Field); + } + + for (size_t i = 0; i < BlockDeclRefDecls.size(); ++i) { + const Expr *E = BlockDeclRefDecls[i]; + const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); + clang::IdentifierInfo *Name = 0; + if (BDRE) { + const ValueDecl *D = BDRE->getDecl(); + Name = &Idents.get(D->getName()); + } + QualType FieldType = E->getType(); + + if (BDRE && BDRE->isByRef()) + FieldType = BuildByRefType(BDRE->getDecl()->getNameAsCString(), + FieldType); + + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + Name, FieldType, /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); + T->addDecl(Field); + } + + T->completeDefinition(*this); + + return getPointerType(getTagDeclType(T)); +} + void ASTContext::setObjCFastEnumerationStateType(QualType T) { const RecordType *Rec = T->getAs<RecordType>(); assert(Rec && "Invalid ObjCFAstEnumerationStateType"); @@ -2945,6 +3185,7 @@ static void EncodeBitField(const ASTContext *Context, std::string& S, S += llvm::utostr(N); } +// FIXME: Use SmallString for accumulating string. void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, bool ExpandPointedToStructures, bool ExpandStructures, @@ -3420,7 +3661,7 @@ Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const { /// compatible. static bool areCompatVectorTypes(const VectorType *LHS, const VectorType *RHS) { - assert(LHS->isCanonical() && RHS->isCanonical()); + assert(LHS->isCanonicalUnqualified() && RHS->isCanonicalUnqualified()); return LHS->getElementType() == RHS->getElementType() && LHS->getNumElements() == RHS->getNumElements(); } @@ -3979,7 +4220,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { unsigned ASTContext::getIntWidth(QualType T) { if (T == BoolTy) return 1; - if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) { + if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) { return FWIT->getWidth(); } // For builtin types, just use the standard type sizing method @@ -3988,10 +4229,18 @@ unsigned ASTContext::getIntWidth(QualType T) { QualType ASTContext::getCorrespondingUnsignedType(QualType T) { assert(T->isSignedIntegerType() && "Unexpected type"); - if (const EnumType* ETy = T->getAs<EnumType>()) + + // Turn <4 x signed int> -> <4 x unsigned int> + if (const VectorType *VTy = T->getAs<VectorType>()) + return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()), + VTy->getNumElements()); + + // For enums, we return the unsigned version of the base type. + if (const EnumType *ETy = T->getAs<EnumType>()) T = ETy->getDecl()->getIntegerType(); - const BuiltinType* BTy = T->getAs<BuiltinType>(); - assert (BTy && "Unexpected signed integer type"); + + const BuiltinType *BTy = T->getAs<BuiltinType>(); + assert(BTy && "Unexpected signed integer type"); switch (BTy->getKind()) { case BuiltinType::Char_S: case BuiltinType::SChar: diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 4a46eab2e603..b59b45f6467e 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -50,7 +50,7 @@ CXXBasePaths::decl_iterator CXXBasePaths::found_decls_end() { /// different base class subobjects of the same type. BaseType must be /// an unqualified, canonical class type. bool CXXBasePaths::isAmbiguous(QualType BaseType) { - assert(BaseType->isCanonical() && "Base type must be the canonical type"); + assert(BaseType.isCanonical() && "Base type must be the canonical type"); assert(BaseType.hasQualifiers() == 0 && "Base type must be unqualified"); std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; return Subobjects.second + (Subobjects.first? 1 : 0) > 1; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index da7959b16f9f..d270a958f0ae 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -231,6 +231,8 @@ std::string NamedDecl::getQualifiedNameAsString() const { } std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { + // FIXME: Collect contexts, then accumulate names to avoid unnecessary + // std::string thrashing. std::vector<std::string> Names; std::string QualName; const DeclContext *Ctx = getDeclContext(); @@ -252,7 +254,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), P); - Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr); + Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr); } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx)) Names.push_back(ND->getNameAsString()); else @@ -336,8 +338,15 @@ NamedDecl *NamedDecl::getUnderlyingDecl() { //===----------------------------------------------------------------------===// SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { - if (DeclInfo) - return DeclInfo->getTypeLoc().getTypeSpecRange().getBegin(); + if (DeclInfo) { + TypeLoc TL = DeclInfo->getTypeLoc(); + while (true) { + TypeLoc NextTL = TL.getNextTypeLoc(); + if (!NextTL) + return TL.getSourceRange().getBegin(); + TL = NextTL; + } + } return SourceLocation(); } @@ -408,10 +417,15 @@ MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { return getASTContext().getInstantiatedFromStaticDataMember(this); } -void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { +void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); assert(MSI && "Not an instantiated static data member?"); MSI->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + MSI->getPointOfInstantiation().isInvalid()) + MSI->setPointOfInstantiation(PointOfInstantiation); } bool VarDecl::isTentativeDefinition(ASTContext &Context) const { @@ -812,18 +826,39 @@ TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { } void -FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { +FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { if (FunctionTemplateSpecializationInfo *FTSInfo = TemplateOrSpecialization.dyn_cast< - FunctionTemplateSpecializationInfo*>()) + FunctionTemplateSpecializationInfo*>()) { FTSInfo->setTemplateSpecializationKind(TSK); - else if (MemberSpecializationInfo *MSInfo - = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + FTSInfo->getPointOfInstantiation().isInvalid()) + FTSInfo->setPointOfInstantiation(PointOfInstantiation); + } else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) { MSInfo->setTemplateSpecializationKind(TSK); - else + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + MSInfo->getPointOfInstantiation().isInvalid()) + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } else assert(false && "Function cannot have a template specialization kind"); } +SourceLocation FunctionDecl::getPointOfInstantiation() const { + if (FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast< + FunctionTemplateSpecializationInfo*>()) + return FTSInfo->getPointOfInstantiation(); + else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) + return MSInfo->getPointOfInstantiation(); + + return SourceLocation(); +} + bool FunctionDecl::isOutOfLine() const { if (Decl::isOutOfLine()) return true; diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 7836b3f827ce..9a1c65416f71 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -299,7 +299,7 @@ void TemplateArgumentListBuilder::Append(const TemplateArgument& Arg) { switch (Arg.getKind()) { default: break; case TemplateArgument::Type: - assert(Arg.getAsType()->isCanonical() && "Type must be canonical!"); + assert(Arg.getAsType().isCanonical() && "Type must be canonical!"); break; } diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 101ddd250933..56a597570dd0 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -51,7 +51,7 @@ public: bool operator<(DeclarationName LHS, DeclarationName RHS) { if (IdentifierInfo *LhsId = LHS.getAsIdentifierInfo()) if (IdentifierInfo *RhsId = RHS.getAsIdentifierInfo()) - return strcmp(LhsId->getName(), RhsId->getName()) < 0; + return LhsId->getName() < RhsId->getName(); return LHS.getAsOpaqueInteger() < RHS.getAsOpaqueInteger(); } @@ -60,7 +60,7 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) { DeclarationName::DeclarationName(Selector Sel) { if (!Sel.getAsOpaquePtr()) { - Ptr = StoredObjCZeroArgSelector; + Ptr = 0; return; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 0e4a29f916fa..a4de3e5b0f7a 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -426,6 +426,18 @@ const char *CastExpr::getCastKindName() const { return "IntegralToPointer"; case CastExpr::CK_PointerToIntegral: return "PointerToIntegral"; + case CastExpr::CK_ToVoid: + return "ToVoid"; + case CastExpr::CK_VectorSplat: + return "VectorSplat"; + case CastExpr::CK_IntegralCast: + return "IntegralCast"; + case CastExpr::CK_IntegralToFloating: + return "IntegralToFloating"; + case CastExpr::CK_FloatingToIntegral: + return "FloatingToIntegral"; + case CastExpr::CK_FloatingCast: + return "FloatingCast"; } assert(0 && "Unhandled cast kind!"); @@ -1740,40 +1752,36 @@ unsigned ExtVectorElementExpr::getNumElements() const { /// containsDuplicateElements - Return true if any element access is repeated. bool ExtVectorElementExpr::containsDuplicateElements() const { - const char *compStr = Accessor->getName(); - unsigned length = Accessor->getLength(); + // FIXME: Refactor this code to an accessor on the AST node which returns the + // "type" of component access, and share with code below and in Sema. + llvm::StringRef Comp = Accessor->getName(); // Halving swizzles do not contain duplicate elements. - if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || - !strcmp(compStr, "even") || !strcmp(compStr, "odd")) + if (Comp == "hi" || Comp == "lo" || Comp == "even" || Comp == "odd") return false; // Advance past s-char prefix on hex swizzles. - if (*compStr == 's' || *compStr == 'S') { - compStr++; - length--; - } + if (Comp[0] == 's' || Comp[0] == 'S') + Comp = Comp.substr(1); - for (unsigned i = 0; i != length-1; i++) { - const char *s = compStr+i; - for (const char c = *s++; *s; s++) - if (c == *s) + for (unsigned i = 0, e = Comp.size(); i != e; ++i) + if (Comp.substr(i + 1).find(Comp[i]) != llvm::StringRef::npos) return true; - } + return false; } /// getEncodedElementAccess - We encode the fields as a llvm ConstantArray. void ExtVectorElementExpr::getEncodedElementAccess( llvm::SmallVectorImpl<unsigned> &Elts) const { - const char *compStr = Accessor->getName(); - if (*compStr == 's' || *compStr == 'S') - compStr++; + llvm::StringRef Comp = Accessor->getName(); + if (Comp[0] == 's' || Comp[0] == 'S') + Comp = Comp.substr(1); - bool isHi = !strcmp(compStr, "hi"); - bool isLo = !strcmp(compStr, "lo"); - bool isEven = !strcmp(compStr, "even"); - bool isOdd = !strcmp(compStr, "odd"); + bool isHi = Comp == "hi"; + bool isLo = Comp == "lo"; + bool isEven = Comp == "even"; + bool isOdd = Comp == "odd"; for (unsigned i = 0, e = getNumElements(); i != e; ++i) { uint64_t Index; @@ -1787,7 +1795,7 @@ void ExtVectorElementExpr::getEncodedElementAccess( else if (isOdd) Index = 2 * i + 1; else - Index = ExtVectorType::getAccessorIdx(compStr[i]); + Index = ExtVectorType::getAccessorIdx(Comp[i]); Elts.push_back(Index); } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 3a838fadafa4..6e0da4714912 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -117,7 +117,7 @@ void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { } const char *LabelStmt::getName() const { - return getID()->getName(); + return getID()->getNameStart(); } // This is defined here to avoid polluting Stmt.h with importing Expr.h diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 0465999a94cc..cf71d6b986a2 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -244,7 +244,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // print a free standing tag decl (e.g. "struct x;"). const char *tagname; if (const IdentifierInfo *II = TD->getIdentifier()) - tagname = II->getName(); + tagname = II->getNameStart(); else tagname = "<anonymous>"; fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname); @@ -253,7 +253,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // print using-directive decl (e.g. "using namespace x;") const char *ns; if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier()) - ns = II->getName(); + ns = II->getNameStart(); else ns = "<anonymous>"; fprintf(F, "\"%s %s;\"",UD->getDeclKindName(), ns); @@ -403,7 +403,7 @@ void StmtDumper::VisitMemberExpr(MemberExpr *Node) { } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { DumpExpr(Node); - fprintf(F, " %s", Node->getAccessor().getName()); + fprintf(F, " %s", Node->getAccessor().getNameStart()); } void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) { DumpExpr(Node); @@ -495,7 +495,7 @@ void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { DumpExpr(Node); fprintf(F, " selector=%s", Node->getSelector().getAsString().c_str()); IdentifierInfo* clsName = Node->getClassName(); - if (clsName) fprintf(F, " class=%s", clsName->getName()); + if (clsName) fprintf(F, " class=%s", clsName->getNameStart()); } void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 05d0c2683545..2af19765dfaa 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1289,7 +1289,7 @@ void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context, return; } - if (Policy.Dump) { + if (Policy.Dump && &Context) { dump(Context.getSourceManager()); return; } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0293862baedb..5fb0178834ff 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -37,18 +37,6 @@ void Type::Destroy(ASTContext& C) { C.Deallocate(this); } -void ConstantArrayWithExprType::Destroy(ASTContext& C) { - // FIXME: destruction of SizeExpr commented out due to resource contention. - // SizeExpr->Destroy(C); - // See FIXME in SemaDecl.cpp:1536: if we were able to either steal - // or clone the SizeExpr there, then here we could freely delete it. - // Since we do not know how to steal or clone, we keep a pointer to - // a shared resource, but we cannot free it. - // (There probably is a trivial solution ... for people knowing clang!). - this->~ConstantArrayWithExprType(); - C.Deallocate(this); -} - void VariableArrayType::Destroy(ASTContext& C) { if (SizeExpr) SizeExpr->Destroy(C); @@ -177,8 +165,6 @@ bool Type::isDerivedType() const { case Pointer: case VariableArray: case ConstantArray: - case ConstantArrayWithExpr: - case ConstantArrayWithoutExpr: case IncompleteArray: case FunctionProto: case FunctionNoProto: @@ -642,6 +628,7 @@ bool Type::isSpecifierType() const { case TypeOfExpr: case TypeOf: case TemplateTypeParm: + case SubstTemplateTypeParm: case TemplateSpecialization: case QualifiedName: case Typename: @@ -737,18 +724,6 @@ void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType(), 0, 0); } -void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID, - QualType OIT, ObjCProtocolDecl **protocols, - unsigned NumProtocols) { - ID.AddPointer(OIT.getAsOpaquePtr()); - for (unsigned i = 0; i != NumProtocols; i++) - ID.AddPointer(protocols[i]); -} - -void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), &Protocols[0], getNumProtocols()); -} - /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to /// potentially looking through *all* consequtive typedefs. This returns the /// sum of the type qualifiers, so if you have: @@ -1072,10 +1047,10 @@ void LValueReferenceType::getAsStringInternal(std::string &S, const PrintingPoli // Handle things like 'int (&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(getPointeeType())) + if (isa<ArrayType>(getPointeeTypeAsWritten())) S = '(' + S + ')'; - getPointeeType().getAsStringInternal(S, Policy); + getPointeeTypeAsWritten().getAsStringInternal(S, Policy); } void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { @@ -1083,10 +1058,10 @@ void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPoli // Handle things like 'int (&&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(getPointeeType())) + if (isa<ArrayType>(getPointeeTypeAsWritten())) S = '(' + S + ')'; - getPointeeType().getAsStringInternal(S, Policy); + getPointeeTypeAsWritten().getAsStringInternal(S, Policy); } void MemberPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { @@ -1111,29 +1086,6 @@ void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy getElementType().getAsStringInternal(S, Policy); } -void ConstantArrayWithExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - if (Policy.ConstantArraySizeAsWritten) { - std::string SStr; - llvm::raw_string_ostream s(SStr); - getSizeExpr()->printPretty(s, 0, Policy); - S += '['; - S += s.str(); - S += ']'; - getElementType().getAsStringInternal(S, Policy); - } - else - ConstantArrayType::getAsStringInternal(S, Policy); -} - -void ConstantArrayWithoutExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - if (Policy.ConstantArraySizeAsWritten) { - S += "[]"; - getElementType().getAsStringInternal(S, Policy); - } - else - ConstantArrayType::getAsStringInternal(S, Policy); -} - void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += "[]"; @@ -1290,7 +1242,7 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy void TypedefType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; - InnerString = getDecl()->getIdentifier()->getName() + InnerString; + InnerString = getDecl()->getIdentifier()->getName().str() + InnerString; } void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { @@ -1301,7 +1253,11 @@ void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const P InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' + llvm::utostr_32(Index) + InnerString; else - InnerString = Name->getName() + InnerString; + InnerString = Name->getName().str() + InnerString; +} + +void SubstTemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + getReplacementType().getAsStringInternal(InnerString, Policy); } std::string @@ -1495,25 +1451,6 @@ void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, InnerString = ObjCQIString + InnerString; } -void ObjCProtocolListType::getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - - std::string ObjCQIString = getBaseType().getAsString(Policy); - ObjCQIString += '<'; - bool isFirst = true; - for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { - if (isFirst) - isFirst = false; - else - ObjCQIString += ','; - ObjCQIString += (*I)->getNameAsString(); - } - ObjCQIString += '>'; - InnerString = ObjCQIString + InnerString; -} - void ElaboratedType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { std::string TypeStr; @@ -1534,11 +1471,11 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName(); const char *ID; if (const IdentifierInfo *II = getDecl()->getIdentifier()) - ID = II->getName(); + ID = II->getNameStart(); else if (TypedefDecl *Typedef = getDecl()->getTypedefForAnonDecl()) { Kind = 0; assert(Typedef->getIdentifier() && "Typedef without identifier?"); - ID = Typedef->getIdentifier()->getName(); + ID = Typedef->getIdentifier()->getNameStart(); } else ID = "<anonymous>"; @@ -1573,7 +1510,7 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), Policy); - MyPart = Spec->getIdentifier()->getName() + TemplateArgsStr; + MyPart = Spec->getIdentifier()->getName().str() + TemplateArgsStr; } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl()) MyPart = Typedef->getIdentifier()->getName(); diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 04e708370af3..50a512028e96 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -20,55 +20,32 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - -/// \brief Return the source range for the visited TypeSpecLoc. -class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { -public: -#define ABSTRACT_TYPELOC(CLASS) + class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - SourceRange Visit##CLASS(CLASS TyLoc) { return TyLoc.getSourceRange(); } + SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getSourceRange(); \ + } #include "clang/AST/TypeLocNodes.def" - - SourceRange VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A typeloc wrapper was not handled!"); - return SourceRange(); - } -}; - -} - -SourceRange TypeLoc::getSourceRange() const { - if (isNull()) - return SourceRange(); - return TypeLocRanger().Visit(*this); + }; } -/// \brief Find the TypeSpecLoc that is part of this TypeLoc. -TypeSpecLoc TypeLoc::getTypeSpecLoc() const { - if (isNull()) - return TypeSpecLoc(); - UnqualTypeLoc Cur = getUnqualifiedLoc(); - if (const DeclaratorLoc *DL = dyn_cast<DeclaratorLoc>(&Cur)) - return DL->getTypeSpecLoc(); - return cast<TypeSpecLoc>(Cur); +SourceRange TypeLoc::getSourceRangeImpl(TypeLoc TL) { + if (TL.isNull()) return SourceRange(); + return TypeLocRanger().Visit(TL); } namespace { - -/// \brief Report the full source info data size for the visited TypeLoc. -class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { -public: -#define ABSTRACT_TYPELOC(CLASS) + class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - unsigned Visit##CLASS(CLASS TyLoc) { return TyLoc.getFullDataSize(); } + unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getFullDataSize(); \ + } #include "clang/AST/TypeLocNodes.def" - - unsigned VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A type loc wrapper was not handled!"); - return 0; - } -}; - + }; } /// \brief Returns the size of the type source info data block. @@ -78,138 +55,42 @@ unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { } namespace { - -/// \brief Return the "next" TypeLoc for the visited TypeLoc, e.g for "int*" the -/// TypeLoc is a PointerLoc and next TypeLoc is for "int". -class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { -public: -#define TYPELOC(CLASS, PARENT) -#define DECLARATOR_TYPELOC(CLASS, TYPE) \ - TypeLoc Visit##CLASS(CLASS TyLoc); + class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getNextTypeLoc(); \ + } #include "clang/AST/TypeLocNodes.def" - - TypeLoc VisitTypeSpecLoc(TypeLoc TyLoc) { return TypeLoc(); } - TypeLoc VisitObjCProtocolListLoc(ObjCProtocolListLoc TL); - TypeLoc VisitQualifiedLoc(QualifiedLoc TyLoc) { - return TyLoc.getUnqualifiedLoc(); - } - - TypeLoc VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A declarator loc wrapper was not handled!"); - return TypeLoc(); - } -}; - -} - -TypeLoc NextLoc::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) { - return TL.getBaseTypeLoc(); -} - -TypeLoc NextLoc::VisitPointerLoc(PointerLoc TL) { - return TL.getPointeeLoc(); -} -TypeLoc NextLoc::VisitMemberPointerLoc(MemberPointerLoc TL) { - return TL.getPointeeLoc(); -} -TypeLoc NextLoc::VisitBlockPointerLoc(BlockPointerLoc TL) { - return TL.getPointeeLoc(); -} -TypeLoc NextLoc::VisitReferenceLoc(ReferenceLoc TL) { - return TL.getPointeeLoc(); -} -TypeLoc NextLoc::VisitFunctionLoc(FunctionLoc TL) { - return TL.getResultLoc(); -} -TypeLoc NextLoc::VisitArrayLoc(ArrayLoc TL) { - return TL.getElementLoc(); + }; } /// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the /// TypeLoc is a PointerLoc and next TypeLoc is for "int". -TypeLoc TypeLoc::getNextTypeLoc() const { - //llvm::errs() << "getNextTypeLoc: Ty=" << Ty << ", Data=" << Data << "\n"; - TypeLoc Tmp = NextLoc().Visit(*this); - //llvm::errs() << " result: Ty=" << Tmp.Ty << ", Data=" << Tmp.Data << "\n"; - return Tmp; +TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) { + return NextLoc().Visit(TL); } -//===----------------------------------------------------------------------===// -// TypeSpecLoc Implementation -//===----------------------------------------------------------------------===// - namespace { -class TypeSpecChecker : public TypeLocVisitor<TypeSpecChecker, bool> { -public: - bool VisitTypeSpecLoc(TypeSpecLoc TyLoc) { return true; } -}; - -} - -bool TypeSpecLoc::classof(const UnqualTypeLoc *TL) { - return TypeSpecChecker().Visit(*TL); -} - -//===----------------------------------------------------------------------===// -// DeclaratorLoc Implementation -//===----------------------------------------------------------------------===// - -namespace { - -/// \brief Return the TypeSpecLoc for the visited DeclaratorLoc. -class TypeSpecGetter : public TypeLocVisitor<TypeSpecGetter, TypeSpecLoc> { -public: -#define TYPELOC(CLASS, PARENT) -#define DECLARATOR_TYPELOC(CLASS, TYPE) \ - TypeSpecLoc Visit##CLASS(CLASS TyLoc) { return TyLoc.getTypeSpecLoc(); } + struct TypeLocInitializer : public TypeLocVisitor<TypeLocInitializer> { + SourceLocation Loc; + TypeLocInitializer(SourceLocation Loc) : Loc(Loc) {} + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + TyLoc.initializeLocal(Loc); \ + } #include "clang/AST/TypeLocNodes.def" - - TypeSpecLoc VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A declarator loc wrapper was not handled!"); - return TypeSpecLoc(); - } - - TypeSpecLoc VisitQualifiedLoc(QualifiedLoc TyLoc) { - return Visit(TyLoc.getUnqualifiedLoc()); - } -}; - -} - -/// \brief Find the TypeSpecLoc that is part of this DeclaratorLoc. -TypeSpecLoc DeclaratorLoc::getTypeSpecLoc() const { - return TypeSpecGetter().Visit(*this); -} - -namespace { - -class DeclaratorLocChecker : public TypeLocVisitor<DeclaratorLocChecker, bool> { -public: - bool VisitDeclaratorLoc(DeclaratorLoc TyLoc) { return true; } -}; - -} - -bool DeclaratorLoc::classof(const UnqualTypeLoc *TL) { - return DeclaratorLocChecker().Visit(*TL); -} - -//===----------------------------------------------------------------------===// -// DefaultTypeSpecLoc Implementation -//===----------------------------------------------------------------------===// - -namespace { - -class DefaultTypeSpecLocChecker : - public TypeLocVisitor<DefaultTypeSpecLocChecker, bool> { -public: - bool VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { return true; } -}; - + }; } -bool DefaultTypeSpecLoc::classofType(const Type *Ty) { - return - DefaultTypeSpecLocChecker().Visit(UnqualTypeLoc(const_cast<Type*>(Ty), 0)); +/// \brief Initializes a type location, and all of its children +/// recursively, as if the entire tree had been written in the +/// given location. +void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) { + do { + TypeLocInitializer(Loc).Visit(TL); + } while ((TL = TL.getNextTypeLoc())); } - diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index a4cb66be04b3..640912ad6b39 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -33,6 +33,12 @@ AnalysisContextManager::~AnalysisContextManager() { delete I->second; } +void AnalysisContextManager::clear() { + for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) + delete I->second; + Contexts.clear(); +} + Stmt *AnalysisContext::getBody() { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) return FD->getBody(); @@ -103,6 +109,21 @@ void ScopeContext::Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, ID.AddPointer(s); } +LocationContextManager::~LocationContextManager() { + clear(); +} + +void LocationContextManager::clear() { + for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(), + E = Contexts.end(); I != E; ) { + LocationContext *LC = &*I; + ++I; + delete LC; + } + + Contexts.clear(); +} + StackFrameContext* LocationContextManager::getStackFrame(AnalysisContext *ctx, const LocationContext *parent, diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index af300f36fa72..aa2d0ab5a763 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -45,9 +45,9 @@ static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { } static const char* GetReceiverNameType(const ObjCMessageExpr* ME) { - const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); - return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName() - : NULL; + if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME)) + return ReceiverType->getDecl()->getIdentifier()->getNameStart(); + return NULL; } namespace { @@ -62,7 +62,7 @@ class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { BugReporter& BR; ASTContext &Ctx; - bool isNSString(const ObjCInterfaceType *T, const char* suffix); + bool isNSString(const ObjCInterfaceType *T, llvm::StringRef suffix); bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME); void Warn(ExplodedNode* N, const Expr* E, const std::string& s); @@ -114,18 +114,8 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode* N, if (!ReceiverType) return false; - const char* name = ReceiverType->getDecl()->getIdentifier()->getName(); - - if (!name) - return false; - - if (name[0] != 'N' || name[1] != 'S') - return false; - - name += 2; - - // FIXME: Make all of this faster. - if (isNSString(ReceiverType, name)) + if (isNSString(ReceiverType, + ReceiverType->getDecl()->getIdentifier()->getName())) return AuditNSString(N, ME); return false; @@ -158,8 +148,8 @@ bool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) { //===----------------------------------------------------------------------===// bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T, - const char* suffix) { - return !strcmp("String", suffix) || !strcmp("MutableString", suffix); + llvm::StringRef ClassName) { + return ClassName == "NSString" || ClassName == "NSMutableString"; } bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N, diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index a4f451f36490..d81d83c7bfa2 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -49,7 +49,8 @@ public: QualType T = QualType()); const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, - const Expr *E, unsigned Count); + 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)); @@ -623,12 +624,21 @@ StoreManager::BindingsHandler::~BindingsHandler() {} const GRState *BasicStoreManager::InvalidateRegion(const GRState *state, const MemRegion *R, const Expr *E, - unsigned Count) { + unsigned Count, + InvalidatedSymbols *IS) { R = R->getBaseRegion(); if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R))) return state; + if (IS) { + BindingsTy B = GetBindings(state->getStore()); + if (BindingsTy::data_type *Val = B.lookup(R)) { + if (SymbolRef Sym = Val->getAsSymbol()) + IS->insert(Sym); + } + } + QualType T = cast<TypedRegion>(R)->getValueType(R->getContext()); SVal V = ValMgr.getConjuredSymbolVal(R, E, T, Count); return Bind(state, loc::MemRegionVal(R), V); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 7b1d50cb3aee..31417597f798 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/Format.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/OwningPtr.h" using namespace clang; @@ -51,7 +52,7 @@ static SourceLocation GetEndLoc(Decl* D) { /// class VISIBILITY_HIDDEN CFGBuilder { ASTContext *Context; - CFG* cfg; + llvm::OwningPtr<CFG> cfg; CFGBlock* Block; CFGBlock* Succ; @@ -79,8 +80,6 @@ public: ContinueTargetBlock(NULL), BreakTargetBlock(NULL), SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {} - ~CFGBuilder() { delete cfg; } - // buildCFG - Used by external clients to construct the CFG. CFG* buildCFG(Stmt *Statement, ASTContext *C); @@ -195,7 +194,7 @@ static VariableArrayType* FindVA(Type* t) { /// NULL. CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { Context = C; - assert(cfg); + assert(cfg.get()); if (!Statement) return NULL; @@ -210,7 +209,8 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { // Visit the statements and create the CFG. CFGBlock* B = addStmt(Statement); - if (!B) B = Succ; + if (!B) + B = Succ; if (B) { // Finalize the last constructed block. This usually involves reversing the @@ -254,17 +254,7 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { // Create an empty entry block that has no predecessors. cfg->setEntry(createBlock()); - if (badCFG) { - delete cfg; - cfg = NULL; - return NULL; - } - - // NULL out cfg so that repeated calls to the builder will fail and that the - // ownership of the constructed CFG is passed to the caller. - CFG* t = cfg; - cfg = NULL; - return t; + return badCFG ? NULL : cfg.take(); } /// createBlock - Used to lazily create blocks that are connected diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index eb1265dda7ea..c629ad1d9612 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -81,7 +81,7 @@ static NamingConvention deriveNamingConvention(Selector S) { if (!II) return NoConvention; - const char *s = II->getName(); + 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 '_'. @@ -93,12 +93,14 @@ static NamingConvention deriveNamingConvention(Selector S) { // 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; - // Discard whatever 'convention' we - // had already derived since it occurs - // in the prefix. - C = NoConvention; + assert(C == NoConvention); } ++s; continue; @@ -208,41 +210,16 @@ static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) { // Type querying functions. //===----------------------------------------------------------------------===// -static bool hasPrefix(const char* s, const char* prefix) { - if (!prefix) - return true; - - char c = *s; - char cP = *prefix; - - while (c != '\0' && cP != '\0') { - if (c != cP) break; - c = *(++s); - cP = *(++prefix); - } - - return cP == '\0'; -} - -static bool hasSuffix(const char* s, const char* suffix) { - const char* loc = strstr(s, suffix); - return loc && strcmp(suffix, loc) == 0; -} - 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 (1) { - if (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { - const char* TDName = TD->getDecl()->getIdentifier()->getName(); - if (hasPrefix(TDName, prefix) && hasSuffix(TDName, "Ref")) - return true; + 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(); - continue; - } - break; + RetTy = TD->getDecl()->getUnderlyingType(); } if (!Ctx || !name) @@ -254,7 +231,7 @@ static bool isRefType(QualType RetTy, const char* prefix, return false; // Does the name start with the prefix? - return hasPrefix(name, prefix); + return llvm::StringRef(name).startswith(prefix); } //===----------------------------------------------------------------------===// @@ -956,7 +933,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the // function's type. const FunctionType* FT = FD->getType()->getAs<FunctionType>(); - const char* FName = FD->getIdentifier()->getName(); + const char* FName = FD->getIdentifier()->getNameStart(); // Strip away preceding '_'. Doing this here will effect all the checks // down below. @@ -1009,7 +986,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // 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); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,DoNothing); } break; @@ -1432,16 +1409,19 @@ void RetainSummaryManager::InitializeClassMethodSummaries() { addNSObjectClsMethSummary(GetUnarySelector("allocWithZone", Ctx), Summ); // Create the [NSAssertionHandler currentHander] summary. - addClsMethSummary(&Ctx.Idents.get("NSAssertionHandler"), - GetNullarySelector("currentHandler", Ctx), + addClassMethSummary("NSAssertionHandler", "currentHandler", getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC))); // Create the [NSAutoreleasePool addObject:] summary. ScratchArgs = AF.Add(ScratchArgs, 0, Autorelease); - addClsMethSummary(&Ctx.Idents.get("NSAutoreleasePool"), - GetUnarySelector("addObject", Ctx), - getPersistentSummary(RetEffect::MakeNoRet(), - DoNothing, Autorelease)); + addClassMethSummary("NSAutoreleasePool", "addObject", + getPersistentSummary(RetEffect::MakeNoRet(), + DoNothing, Autorelease)); + + // Create a summary for [NSCursor dragCopyCursor]. + addClassMethSummary("NSCursor", "dragCopyCursor", + getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, + DoNothing)); // Create the summaries for [NSObject performSelector...]. We treat // these as 'stop tracking' for the arguments because they are often @@ -2856,14 +2836,13 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, // FIXME: What about layers of ElementRegions? } - // Is the invalidated variable something that we were tracking? - SymbolRef Sym = state->getSValAsScalarOrLoc(R).getAsLocSymbol(); - - // Remove any existing reference-count binding. - if (Sym) - state = state->remove<RefBindings>(Sym); - - state = StoreMgr.InvalidateRegion(state, R, *I, Count); + StoreManager::InvalidatedSymbols IS; + state = StoreMgr.InvalidateRegion(state, R, *I, Count, &IS); + for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), + E = IS.end(); I!=E; ++I) { + // Remove any existing reference-count binding. + state = state->remove<RefBindings>(*I); + } } else { // Nuke all other arguments passed by reference. diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 5079acef54b4..ea0255ded8a9 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -207,7 +207,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // Precondition: the first argument of 'main' is an integer guaranteed // to be > 0. - if (strcmp(FD->getIdentifier()->getName(), "main") == 0 && + if (FD->getIdentifier()->getName() == "main" && FD->getNumParams() > 0) { const ParmVarDecl *PD = FD->getParamDecl(0); QualType T = PD->getType(); @@ -1445,10 +1445,9 @@ static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE, // HACK: Some functions are not marked noreturn, and don't return. // Here are a few hardwired ones. If this takes too long, we can // potentially cache these results. - const char* s = FD->getIdentifier()->getName(); - unsigned n = strlen(s); + const char* s = FD->getIdentifier()->getNameStart(); - switch (n) { + switch (FD->getIdentifier()->getLength()) { default: break; @@ -2788,66 +2787,55 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, SVal RightV = state->getSVal(RHS); BinaryOperator::Opcode Op = B->getOpcode(); - switch (Op) { - case BinaryOperator::Assign: { - - // 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(); - RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count); - } - // Simulate the effects of a "store": bind the value of the RHS - // to the L-Value represented by the LHS. - EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, RightV), - LeftV, RightV); - continue; + if (Op == BinaryOperator::Assign) { + // 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(); + RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count); } - - // FALL-THROUGH. - - default: { - - if (B->isAssignmentOp()) - break; - - // 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. - MakeNode(Dst, B, *I2, state); - } - else - Dst.Add(*I2); - - continue; + + // Simulate the effects of a "store": bind the value of the RHS + // to the L-Value represented by the LHS. + EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, RightV), 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. + MakeNode(Dst, B, *I2, state); } - - state = state->BindExpr(B, Result); - - if (Result.isUndef()) { - // The operands were *not* undefined, but the result is undefined. - // This is a special node that should be flagged as an error. - if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){ - UndefNode->markAsSink(); - UndefResults.insert(UndefNode); - } - continue; + else + Dst.Add(*I2); + + continue; + } + + state = state->BindExpr(B, Result); + + if (Result.isUndef()) { + // The operands were *not* undefined, but the result is undefined. + // This is a special node that should be flagged as an error. + if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){ + UndefNode->markAsSink(); + UndefResults.insert(UndefNode); } - - // Otherwise, create a new node. - MakeNode(Dst, B, *I2, state); continue; } + + // Otherwise, create a new node. + MakeNode(Dst, B, *I2, state); + continue; } assert (B->isCompoundAssignmentOp()); @@ -2875,7 +2863,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, for (ExplodedNodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; ++I3) { - state = GetState(*I3); SVal V = state->getSVal(LHS); diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index cc1ec4b77e48..da24192c9d5a 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -742,11 +742,11 @@ void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { } } -class VISIBILITY_HIDDEN CheckBadDiv : public CheckerVisitor<CheckBadDiv> { +class VISIBILITY_HIDDEN CheckDivZero : public CheckerVisitor<CheckDivZero> { DivZero *BT; public: - CheckBadDiv() : BT(0) {} - ~CheckBadDiv() {} + CheckDivZero() : BT(0) {} + ~CheckDivZero() {} const void *getTag() { static int x; @@ -756,8 +756,8 @@ public: void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); }; -void CheckBadDiv::PreVisitBinaryOperator(CheckerContext &C, - const BinaryOperator *B) { +void CheckDivZero::PreVisitBinaryOperator(CheckerContext &C, + const BinaryOperator *B) { BinaryOperator::Opcode Op = B->getOpcode(); if (Op != BinaryOperator::Div && Op != BinaryOperator::Rem && @@ -792,7 +792,8 @@ void CheckBadDiv::PreVisitBinaryOperator(CheckerContext &C, return; } - // If we get here, then the denom should not be zero. + // If we get here, then the denom should not be zero. We abandon the implicit + // zero denom case for now. if (stateNotZero != C.getState()) C.addTransition(C.GenerateNode(B, stateNotZero)); } @@ -828,5 +829,5 @@ void GRExprEngine::RegisterInternalChecks() { registerCheck(new CheckAttrNonNull()); registerCheck(new CheckUndefinedArg()); registerCheck(new CheckBadCall()); - registerCheck(new CheckBadDiv()); + registerCheck(new CheckDivZero()); } diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 4d96c8f8f401..ae78d1f35ff6 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -21,9 +21,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" - -#include <string.h> -#include <stdio.h> +#include "llvm/Support/raw_ostream.h" using namespace clang; @@ -341,20 +339,19 @@ void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const { for (AnalysisDataTy::decl_iterator I = AD.begin_decl(), E = AD.end_decl(); I!=E; ++I) if (V.getDeclBit(I->second)) { - fprintf(stderr, " %s <", I->first->getIdentifier()->getName()); + llvm::errs() << " " << I->first->getIdentifier()->getName() << " <"; I->first->getLocation().dump(SM); - fprintf(stderr, ">\n"); + llvm::errs() << ">\n"; } } void LiveVariables::dumpBlockLiveness(SourceManager& M) const { for (BlockDataMapTy::iterator I = getBlockDataMap().begin(), E = getBlockDataMap().end(); I!=E; ++I) { - fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n", - I->first->getBlockID()); - + llvm::errs() << "\n[ B" << I->first->getBlockID() + << " (live variables at block exit) ]\n"; dumpLiveness(I->second,M); } - fprintf(stderr,"\n"); + llvm::errs() << "\n"; } diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 9456ab64542c..780772a6f129 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -262,7 +262,8 @@ public: //===-------------------------------------------------------------------===// const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, - const Expr *E, unsigned Count); + const Expr *E, unsigned Count, + InvalidatedSymbols *IS); private: void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R, @@ -455,7 +456,8 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B, const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, const MemRegion *R, const Expr *Ex, - unsigned Count) { + unsigned Count, + InvalidatedSymbols *IS) { ASTContext& Ctx = StateMgr.getContext(); // Strip away casts. @@ -490,9 +492,21 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, if (Optional<SVal> V = getDirectBinding(B, R)) { if (const MemRegion *RV = V->getAsRegion()) WorkList.push_back(RV); + + // A symbol? Mark it touched by the invalidation. + if (IS) { + if (SymbolRef Sym = V->getAsSymbol()) + IS->insert(Sym); + } } - // Handle region. + // Symbolic region? Mark that symbol touched by the invalidation. + if (IS) { + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) + IS->insert(SR->getSymbol()); + } + + // Handle the region itself. if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) || isa<ObjCObjectRegion>(R)) { // Invalidate the region by setting its default value to @@ -1230,8 +1244,8 @@ SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state, const MemRegion *superR = R->getSuperRegion(); - // Check if the super region has a binding. - if (Optional<SVal> V = getDirectBinding(B, superR)) { + // Check if the super region has a default binding. + if (Optional<SVal> V = getDefaultBinding(B, superR)) { if (SymbolRef parentSym = V->getAsSymbol()) return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); @@ -1376,7 +1390,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal 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); + return InvalidateRegion(state, superR, NULL, 0, NULL); } } } @@ -1588,36 +1602,13 @@ RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, //===----------------------------------------------------------------------===// // State pruning. //===----------------------------------------------------------------------===// - -namespace { -class VISIBILITY_HIDDEN RBDNode - : public std::pair<const GRState*, const MemRegion *> { -public: - RBDNode(const GRState *st, const MemRegion *r) - : std::pair<const GRState*, const MemRegion*>(st, r) {} - - const GRState *getState() const { return first; } - const MemRegion *getRegion() const { return second; } -}; - -enum VisitFlag { NotVisited = 0, VisitedFromSubRegion, VisitedFromSuperRegion }; - -class RBDItem : public RBDNode { -private: - const VisitFlag VF; - -public: - RBDItem(const GRState *st, const MemRegion *r, VisitFlag vf) - : RBDNode(st, r), VF(vf) {} - - VisitFlag getVisitFlag() const { return VF; } -}; -} // end anonymous namespace void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) { + typedef std::pair<const GRState*, const MemRegion *> RBDNode; + Store store = state.getStore(); RegionBindings B = GetRegionBindings(store); @@ -1638,27 +1629,26 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Process the "intermediate" roots to find if they are referenced by // real roots. - llvm::SmallVector<RBDItem, 10> WorkList; - llvm::DenseMap<const MemRegion*,unsigned> IntermediateVisited; + llvm::SmallVector<RBDNode, 10> WorkList; + llvm::DenseSet<const MemRegion*> IntermediateVisited; while (!IntermediateRoots.empty()) { const MemRegion* R = IntermediateRoots.back(); IntermediateRoots.pop_back(); - unsigned &visited = IntermediateVisited[R]; - if (visited) + if (IntermediateVisited.count(R)) continue; - visited = 1; + IntermediateVisited.insert(R); if (const VarRegion* VR = dyn_cast<VarRegion>(R)) { if (SymReaper.isLive(Loc, VR->getDecl())) - WorkList.push_back(RBDItem(&state, VR, VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(&state, VR)); continue; } if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) { if (SymReaper.isLive(SR->getSymbol())) - WorkList.push_back(RBDItem(&state, SR, VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(&state, SR)); continue; } @@ -1671,54 +1661,40 @@ 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(RBDItem(&state, *I, VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(&state, *I)); } RegionRoots.clear(); - // Process the worklist. - typedef llvm::DenseMap<std::pair<const GRState*, const MemRegion*>, VisitFlag> - VisitMap; - - VisitMap Visited; + llvm::DenseSet<RBDNode> Visited; while (!WorkList.empty()) { - RBDItem N = WorkList.back(); + RBDNode N = WorkList.back(); WorkList.pop_back(); // Have we visited this node before? - VisitFlag &VF = Visited[N]; - if (VF >= N.getVisitFlag()) + if (Visited.count(N)) continue; + Visited.insert(N); + + const MemRegion *R = N.second; + const GRState *state_N = N.first; - const MemRegion *R = N.getRegion(); - const GRState *state_N = N.getState(); - - // Enqueue subregions? - if (N.getVisitFlag() == VisitedFromSuperRegion) { - RegionStoreSubRegionMap *M; - - if (&state == state_N) - M = SubRegions.get(); - else { - RegionStoreSubRegionMap *& SM = SC[state_N]; - if (!SM) - SM = getRegionStoreSubRegionMap(state_N->getStore()); - M = SM; - } + // Enqueue subregions. + RegionStoreSubRegionMap *M; - RegionStoreSubRegionMap::iterator I, E; - for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I) - WorkList.push_back(RBDItem(state_N, *I, VisitedFromSuperRegion)); - } - - // At this point, if we have already visited this region before, we are - // done. - if (VF != NotVisited) { - VF = N.getVisitFlag(); - continue; + if (&state == state_N) + M = SubRegions.get(); + else { + RegionStoreSubRegionMap *& SM = SC[state_N]; + if (!SM) + SM = getRegionStoreSubRegionMap(state_N->getStore()); + M = SM; } - VF = N.getVisitFlag(); + 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)); + // Enqueue the super region. if (const SubRegion *SR = dyn_cast<SubRegion>(R)) { const MemRegion *superR = SR->getSuperRegion(); @@ -1726,12 +1702,9 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // If 'R' is a field or an element, we want to keep the bindings // for the other fields and elements around. The reason is that // pointer arithmetic can get us to the other fields or elements. - // FIXME: add an assertion that this is always true. - VisitFlag NewVisit = - isa<FieldRegion>(R) || isa<ElementRegion>(R) || isa<ObjCIvarRegion>(R) - ? VisitedFromSuperRegion : VisitedFromSubRegion; - - WorkList.push_back(RBDItem(state_N, superR, NewVisit)); + assert(isa<FieldRegion>(R) || isa<ElementRegion>(R) + || isa<ObjCIvarRegion>(R)); + WorkList.push_back(std::make_pair(state_N, superR)); } } @@ -1752,8 +1725,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, dyn_cast<nonloc::LazyCompoundVal>(V.getPointer())) { const LazyCompoundValData *D = LCV->getCVData(); - WorkList.push_back(RBDItem(D->getState(), D->getRegion(), - VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(D->getState(), D->getRegion())); } else { // Update the set of live symbols. @@ -1763,7 +1735,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // If V is a region, then add it to the worklist. if (const MemRegion *RX = V->getAsRegion()) - WorkList.push_back(RBDItem(state_N, RX, VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(state_N, RX)); } } } @@ -1774,7 +1746,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { const MemRegion* R = I.getKey(); // If this region live? Is so, none of its symbols are dead. - if (Visited.find(std::make_pair(&state, R)) != Visited.end()) + if (Visited.count(std::make_pair(&state, R))) continue; // Remove this dead region from the store. @@ -1820,7 +1792,7 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, void RegionStoreManager::print(Store store, llvm::raw_ostream& OS, const char* nl, const char *sep) { RegionBindings B = GetRegionBindings(store); - OS << "Store (direct bindings):" << nl; + OS << "Store (direct and default bindings):" << nl; for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) OS << ' ' << I.getKey() << " : " << I.getData() << nl; diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp index 636ce15c3326..4487aa9d3028 100644 --- a/lib/Analysis/SimpleSValuator.cpp +++ b/lib/Analysis/SimpleSValuator.cpp @@ -346,16 +346,29 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs); SymbolRef Sym = slhs->getSymbol(); - // Does the symbol simplify to a constant? + // Does the symbol simplify to a constant? If so, "fold" the constant + // by setting 'lhs' to a ConcreteInt and try again. if (Sym->getType(ValMgr.getContext())->isIntegerType()) if (const llvm::APSInt *Constant = state->getSymVal(Sym)) { - // What should we convert it to? - if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){ - BasicValueFactory &BVF = ValMgr.getBasicValueFactory(); - lhs = nonloc::ConcreteInt(BVF.Convert(rhs_I->getValue(), - *Constant)); + // The symbol evaluates to a constant. If necessary, promote the + // folded constant (LHS) to the result type. + BasicValueFactory &BVF = ValMgr.getBasicValueFactory(); + const llvm::APSInt &lhs_I = BVF.Convert(resultTy, *Constant); + lhs = nonloc::ConcreteInt(lhs_I); + + // Also promote the RHS (if necessary). + + // For shifts, it necessary promote the RHS to the result type. + if (BinaryOperator::isShiftOp(op)) continue; + + // Other operators: do an implicit conversion. This shouldn't be + // necessary once we support truncation/extension of symbolic values. + if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){ + rhs = nonloc::ConcreteInt(BVF.Convert(resultTy, rhs_I->getValue())); } + + continue; } if (isa<nonloc::ConcreteInt>(rhs)) { diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 4a29997a2ccc..fbc731311653 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -25,6 +25,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" #include <vector> #include <map> #include <cstring> @@ -82,9 +83,14 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { #ifndef NDEBUG static bool IsFirst = true; if (IsFirst) { - for (unsigned i = 1; i != NumDiagEntries; ++i) + for (unsigned i = 1; i != NumDiagEntries; ++i) { + assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID && + "Diag ID conflict, the enums at the start of clang::diag (in " + "Diagnostic.h) probably need to be increased"); + assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] && "Improperly sorted diag info"); + } IsFirst = false; } #endif @@ -184,6 +190,8 @@ namespace clang { static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT, const char *Modifier, unsigned ML, const char *Argument, unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, llvm::SmallVectorImpl<char> &Output, void *Cookie) { const char *Str = "<can't format argument>"; @@ -222,6 +230,8 @@ Diagnostic::~Diagnostic() { void Diagnostic::pushMappings() { + // Avoids undefined behavior when the stack has to resize. + DiagMappingsStack.reserve(DiagMappingsStack.size() + 1); DiagMappingsStack.push_back(DiagMappingsStack.back()); } @@ -679,6 +689,12 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { const char *DiagStr = getDiags()->getDescription(getID()); const char *DiagEnd = DiagStr+strlen(DiagStr); + /// FormattedArgs - Keep track of all of the arguments formatted by + /// ConvertArgToString and pass them into subsequent calls to + /// ConvertArgToString, allowing the implementation to avoid redundancies in + /// obvious cases. + llvm::SmallVector<Diagnostic::ArgumentValue, 8> FormattedArgs; + while (DiagStr != DiagEnd) { if (DiagStr[0] != '%') { // Append non-%0 substrings to Str if we have one. @@ -726,7 +742,9 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic"); unsigned ArgNo = *DiagStr++ - '0'; - switch (getArgKind(ArgNo)) { + Diagnostic::ArgumentKind Kind = getArgKind(ArgNo); + + switch (Kind) { // ---- STRINGS ---- case Diagnostic::ak_std_string: { const std::string &S = getArgStdStr(ArgNo); @@ -757,9 +775,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); } else { assert(ModifierLen == 0 && "Unknown integer modifier"); - // FIXME: Optimize - std::string S = llvm::itostr(Val); - OutStr.append(S.begin(), S.end()); + llvm::raw_svector_ostream(OutStr) << Val; } break; } @@ -774,10 +790,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); } else { assert(ModifierLen == 0 && "Unknown integer modifier"); - - // FIXME: Optimize - std::string S = llvm::utostr_32(Val); - OutStr.append(S.begin(), S.end()); + llvm::raw_svector_ostream(OutStr) << Val; } break; } @@ -793,9 +806,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { continue; } - OutStr.push_back('\''); - OutStr.append(II->getName(), II->getName() + II->getLength()); - OutStr.push_back('\''); + llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\''; break; } case Diagnostic::ak_qualtype: @@ -803,11 +814,23 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { case Diagnostic::ak_nameddecl: case Diagnostic::ak_nestednamespec: case Diagnostic::ak_declcontext: - getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo), + getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo), Modifier, ModifierLen, - Argument, ArgumentLen, OutStr); + Argument, ArgumentLen, + FormattedArgs.data(), FormattedArgs.size(), + OutStr); break; } + + // Remember this argument info for subsequent formatting operations. Turn + // std::strings into a null terminated string to make it be the same case as + // all the other ones. + if (Kind != Diagnostic::ak_std_string) + FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo))); + else + FormattedArgs.push_back(std::make_pair(Diagnostic::ak_c_string, + (intptr_t)getArgStdStr(ArgNo).c_str())); + } } diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index df86f9d04702..ee4309de937b 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -149,6 +149,41 @@ FileManager::~FileManager() { delete &UniqueFiles; } +void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) { + assert(statCache && "No stat cache provided?"); + if (AtBeginning || StatCache.get() == 0) { + statCache->setNextStatCache(StatCache.take()); + StatCache.reset(statCache); + return; + } + + StatSysCallCache *LastCache = StatCache.get(); + while (LastCache->getNextStatCache()) + LastCache = LastCache->getNextStatCache(); + + LastCache->setNextStatCache(statCache); +} + +void FileManager::removeStatCache(StatSysCallCache *statCache) { + if (!statCache) + return; + + if (StatCache.get() == statCache) { + // This is the first stat cache. + StatCache.reset(StatCache->takeNextStatCache()); + return; + } + + // Find the stat cache in the list. + StatSysCallCache *PrevCache = StatCache.get(); + while (PrevCache && PrevCache->getNextStatCache() != statCache) + PrevCache = PrevCache->getNextStatCache(); + if (PrevCache) + PrevCache->setNextStatCache(statCache->getNextStatCache()); + else + assert(false && "Stat cache not found for removal"); +} + /// getDirectory - Lookup, cache, and verify the specified directory. This /// returns null if the directory doesn't exist. /// @@ -290,8 +325,8 @@ void FileManager::PrintStats() const { } int MemorizeStatCalls::stat(const char *path, struct stat *buf) { - int result = ::stat(path, buf); - + int result = StatSysCallCache::stat(path, buf); + if (result != 0) { // Cache failed 'stat' results. struct stat empty; diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 93c260fdbe17..16aa0c54846a 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/LangOptions.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/raw_ostream.h" #include <cstdio> using namespace clang; @@ -153,7 +154,7 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { unsigned Len = getLength(); if (Len < 2) return tok::pp_not_keyword; - const char *Name = getName(); + const char *Name = getNameStart(); switch (HASH(Len, Name[0], Name[2])) { default: return tok::pp_not_keyword; CASE( 2, 'i', '\0', if); @@ -301,24 +302,15 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { } std::string MultiKeywordSelector::getName() const { - std::string Result; - unsigned Length = 0; + llvm::SmallString<256> Str; + llvm::raw_svector_ostream OS(Str); for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { if (*I) - Length += (*I)->getLength(); - ++Length; // : + OS << (*I)->getName(); + OS << ':'; } - Result.reserve(Length); - - for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { - if (*I) - Result.insert(Result.end(), (*I)->getName(), - (*I)->getName()+(*I)->getLength()); - Result.push_back(':'); - } - - return Result; + return OS.str(); } std::string Selector::getAsString() const { @@ -332,9 +324,10 @@ std::string Selector::getAsString() const { if (getNumArgs() == 0) return II->getName(); - std::string Res = II ? II->getName() : ""; - Res += ":"; - return Res; + if (!II) + return ":"; + + return II->getName().str() + ":"; } // We have a multiple keyword selector (no embedded flags). diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 9cd12493e7a4..8f3c777c2004 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -43,6 +43,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { UIntMaxType = UnsignedLongLong; IntPtrType = SignedLong; WCharType = SignedInt; + WIntType = SignedInt; Char16Type = UnsignedShort; Char32Type = UnsignedInt; Int64Type = SignedLongLong; @@ -73,6 +74,57 @@ const char *TargetInfo::getTypeName(IntType T) { } } +/// getTypeConstantSuffix - Return the constant suffix for the specified +/// integer type enum. For example, SignedLong -> "L". +const char *TargetInfo::getTypeConstantSuffix(IntType T) { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: + case SignedInt: return ""; + case SignedLong: return "L"; + case SignedLongLong: return "LL"; + case UnsignedShort: + case UnsignedInt: return "U"; + case UnsignedLong: return "UL"; + case UnsignedLongLong: return "ULL"; + } +} + +/// getTypeWidth - Return the width (in bits) of the specified integer type +/// enum. For example, SignedInt -> getIntWidth(). +unsigned TargetInfo::getTypeWidth(IntType T) const { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: return getShortWidth(); + case UnsignedShort: return getShortWidth(); + case SignedInt: return getIntWidth(); + case UnsignedInt: return getIntWidth(); + case SignedLong: return getLongWidth(); + case UnsignedLong: return getLongWidth(); + case SignedLongLong: return getLongLongWidth(); + case UnsignedLongLong: return getLongLongWidth(); + }; +} + +/// getTypeSigned - Return whether an integer types is signed. Returns true if +/// the type is signed; false otherwise. +bool TargetInfo::getTypeSigned(IntType T) const { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: + case SignedInt: + case SignedLong: + case SignedLongLong: + return true; + case UnsignedShort: + case UnsignedInt: + case UnsignedLong: + case UnsignedLongLong: + return false; + }; +} + + //===----------------------------------------------------------------------===// diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 1d4d1235c963..66d6824b6f29 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -320,6 +320,27 @@ public: : OSTargetInfo<Target>(triple) {} }; +// AuroraUX target +template<typename Target> +class AuroraUXTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + std::vector<char> &Defs) const { + DefineStd(Defs, "sun", Opts); + DefineStd(Defs, "unix", Opts); + Define(Defs, "__ELF__"); + Define(Defs, "__svr4__"); + Define(Defs, "__SVR4"); + } +public: + AuroraUXTargetInfo(const std::string& triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + this->WCharType = this->SignedLong; + // FIXME: WIntType should be SignedLong + } +}; + // Solaris target template<typename Target> class SolarisTargetInfo : public OSTargetInfo<Target> { @@ -1456,6 +1477,14 @@ void SparcV8TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, } // end anonymous namespace. namespace { +class AuroraUXSparcV8TargetInfo : public AuroraUXTargetInfo<SparcV8TargetInfo> { +public: + AuroraUXSparcV8TargetInfo(const std::string& triple) : + AuroraUXTargetInfo<SparcV8TargetInfo>(triple) { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + } +}; class SolarisSparcV8TargetInfo : public SolarisTargetInfo<SparcV8TargetInfo> { public: SolarisSparcV8TargetInfo(const std::string& triple) : @@ -1573,8 +1602,8 @@ namespace { } virtual bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const { - // FIXME: implement - return true; + // No target constraints for now. + return false; } virtual const char *getClobbers() const { // FIXME: Is this really right? @@ -1846,6 +1875,8 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { return new PPC64TargetInfo(T); case llvm::Triple::sparc: + if (os == llvm::Triple::AuroraUX) + return new AuroraUXSparcV8TargetInfo(T); if (os == llvm::Triple::Solaris) return new SolarisSparcV8TargetInfo(T); return new SparcV8TargetInfo(T); @@ -1858,6 +1889,8 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { case llvm::Triple::x86: switch (os) { + case llvm::Triple::AuroraUX: + return new AuroraUXTargetInfo<X86_32TargetInfo>(T); case llvm::Triple::Darwin: return new DarwinI386TargetInfo(T); case llvm::Triple::Linux: @@ -1884,6 +1917,8 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { case llvm::Triple::x86_64: switch (os) { + case llvm::Triple::AuroraUX: + return new AuroraUXTargetInfo<X86_64TargetInfo>(T); case llvm::Triple::Darwin: return new DarwinX86_64TargetInfo(T); case llvm::Triple::Linux: diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 736425e01276..682cf5da1e72 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -73,29 +73,60 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() { return NSConcreteStackBlock; } -static void CollectBlockDeclRefInfo(const Stmt *S, - CodeGenFunction::BlockInfo &Info) { +static void CollectBlockDeclRefInfo( + const Stmt *S, CodeGenFunction::BlockInfo &Info, + llvm::SmallSet<const DeclContext *, 16> &InnerContexts) { for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I) if (*I) - CollectBlockDeclRefInfo(*I, Info); + CollectBlockDeclRefInfo(*I, Info, InnerContexts); - if (const BlockDeclRefExpr *DE = dyn_cast<BlockDeclRefExpr>(S)) { + // We want to ensure we walk down into block literals so we can find + // all nested BlockDeclRefExprs. + if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) { + InnerContexts.insert(cast<DeclContext>(BE->getBlockDecl())); + CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); + } + + if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { // FIXME: Handle enums. - if (isa<FunctionDecl>(DE->getDecl())) + if (isa<FunctionDecl>(BDRE->getDecl())) return; - if (DE->isByRef()) - Info.ByRefDeclRefs.push_back(DE); - else - Info.ByCopyDeclRefs.push_back(DE); + // Only Decls that escape are added. + if (!InnerContexts.count(BDRE->getDecl()->getDeclContext())) + Info.DeclRefs.push_back(BDRE); } } /// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be /// declared as a global variable instead of on the stack. static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) { - return Info.ByRefDeclRefs.empty() && Info.ByCopyDeclRefs.empty(); + return Info.DeclRefs.empty(); +} + +/// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to +/// ensure we can generate the debug information for the parameter for the block +/// invoke function. +static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info, + CodeGenFunction *CGF) { + // Always allocate self, as it is often handy in the debugger, even if there + // is no codegen in the block that uses it. This is also useful to always do + // this as if we didn't, we'd have to figure out all code that uses a self + // pointer, including implicit uses. + if (const ObjCMethodDecl *OMD + = dyn_cast_or_null<ObjCMethodDecl>(CGF->CurFuncDecl)) { + ImplicitParamDecl *SelfDecl = OMD->getSelfDecl(); + BlockDeclRefExpr *BDRE = new (CGF->getContext()) + BlockDeclRefExpr(SelfDecl, + SelfDecl->getType(), SourceLocation(), false); + CGF->AllocateBlockDecl(BDRE); + } + + // FIXME: Also always forward the this pointer in C++ as well. + + for (size_t i = 0; i < Info.DeclRefs.size(); ++i) + CGF->AllocateBlockDecl(Info.DeclRefs[i]); } // FIXME: Push most into CGM, passing down a few bits, like current function @@ -104,7 +135,9 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { std::string Name = CurFn->getName(); CodeGenFunction::BlockInfo Info(0, Name.c_str()); - CollectBlockDeclRefInfo(BE->getBody(), Info); + llvm::SmallSet<const DeclContext *, 16> InnerContexts; + InnerContexts.insert(BE->getBlockDecl()); + CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); // Check if the block can be global. // FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like @@ -159,7 +192,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { if (subBlockDeclRefDecls.size() == 0) { // __descriptor - Elts[4] = BuildDescriptorBlockDecl(subBlockHasCopyDispose, subBlockSize, 0, 0); + Elts[4] = BuildDescriptorBlockDecl(subBlockHasCopyDispose, subBlockSize, + 0, 0); // Optimize to being a global block. Elts[0] = CGM.getNSConcreteGlobalBlock(); @@ -269,7 +303,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::Value *BlockLiteral = LoadBlockStruct(); Loc = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), offset), "block.literal"); Ty = llvm::PointerType::get(Ty, 0); @@ -391,10 +425,6 @@ const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() { return GenericExtendedBlockLiteralType; } -bool BlockFunction::BlockRequiresCopying(QualType Ty) { - return CGM.BlockRequiresCopying(Ty); -} - RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { const BlockPointerType *BPT = E->getCallee()->getType()->getAs<BlockPointerType>(); @@ -447,24 +477,34 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { return EmitCall(FnInfo, Func, Args); } -llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { +uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { const ValueDecl *VD = E->getDecl(); - uint64_t &offset = BlockDecls[VD]; - // See if we have already allocated an offset for this variable. - if (offset == 0) { - // Don't run the expensive check, unless we have to. - if (!BlockHasCopyDispose && BlockRequiresCopying(E->getType())) + if (offset) + return offset; + + // Don't run the expensive check, unless we have to. + if (!BlockHasCopyDispose) + if (E->isByRef() + || BlockRequiresCopying(E->getType())) BlockHasCopyDispose = true; - // if not, allocate one now. - offset = getBlockOffset(E); - } + + // if not, allocate one now. + offset = getBlockOffset(E); + + return offset; +} + +llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { + const ValueDecl *VD = E->getDecl(); + uint64_t offset = AllocateBlockDecl(E); + llvm::Value *BlockLiteral = LoadBlockStruct(); llvm::Value *V = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), offset), "block.literal"); if (E->isByRef()) { @@ -576,7 +616,10 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { } llvm::Value *CodeGenFunction::LoadBlockStruct() { - return Builder.CreateLoad(LocalDeclMap[getBlockStructDecl()], "self"); + llvm::Value *V = Builder.CreateLoad(LocalDeclMap[getBlockStructDecl()], + "self"); + // For now, we codegen based upon byte offsets. + return Builder.CreateBitCast(V, PtrToInt8Ty); } llvm::Function * @@ -605,14 +648,8 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, LocalDeclMap[VD] = i->second; } - // FIXME: We need to rearrange the code for copy/dispose so we have this - // sooner, so we can calculate offsets correctly. - if (!BlockHasCopyDispose) - BlockOffset = CGM.getTargetData() - .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8; - else - BlockOffset = CGM.getTargetData() - .getTypeStoreSizeInBits(CGM.getGenericExtendedBlockLiteralType()) / 8; + BlockOffset = CGM.getTargetData() + .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8; BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; const FunctionType *BlockFunctionType = BExpr->getFunctionType(); @@ -630,13 +667,22 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, FunctionArgList Args; + CurFuncDecl = OuterFuncDecl; + const BlockDecl *BD = BExpr->getBlockDecl(); + IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); + + // Allocate all BlockDeclRefDecls, so we can calculate the right ParmTy below. + AllocateAllBlockDeclRefs(Info, this); + + QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose, + BlockDeclRefDecls); // FIXME: This leaks ImplicitParamDecl *SelfDecl = ImplicitParamDecl::Create(getContext(), 0, - SourceLocation(), 0, - getContext().getPointerType(getContext().VoidTy)); + SourceLocation(), II, + ParmTy); Args.push_back(std::make_pair(SelfDecl, SelfDecl->getType())); BlockStructDecl = SelfDecl; @@ -758,11 +804,13 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, FunctionArgList Args; // FIXME: This leaks ImplicitParamDecl *Dst = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Dst, Dst->getType())); ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); @@ -843,7 +891,8 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, FunctionArgList Args; // FIXME: This leaks ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); @@ -922,13 +971,15 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { FunctionArgList Args; // FIXME: This leaks ImplicitParamDecl *Dst = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Dst, Dst->getType())); // FIXME: This leaks ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); @@ -991,7 +1042,8 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, FunctionArgList Args; // FIXME: This leaks ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 3a860c0d3c36..3ab4efb71bee 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -115,15 +115,8 @@ public: PtrToInt8Ty = llvm::Type::getInt8PtrTy(M.getContext()); } - bool BlockRequiresCopying(QualType Ty) { - if (Ty->isBlockPointerType()) - return true; - if (getContext().isObjCNSObjectType(Ty)) - return true; - if (Ty->isObjCObjectPointerType()) - return true; - return false; - } + bool BlockRequiresCopying(QualType Ty) + { return getContext().BlockRequiresCopying(Ty); } }; class BlockFunction : public BlockBase { @@ -165,11 +158,7 @@ public: /// ByCopyDeclRefs - Variables from parent scopes that have been imported /// into this block. - llvm::SmallVector<const BlockDeclRefExpr *, 8> ByCopyDeclRefs; - - // ByRefDeclRefs - __block variables from parent scopes that have been - // imported into this block. - llvm::SmallVector<const BlockDeclRefExpr *, 8> ByRefDeclRefs; + llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs; BlockInfo(const llvm::Type *blt, const char *n) : BlockLiteralTy(blt), Name(n) { @@ -228,7 +217,8 @@ public: llvm::Value *getBlockObjectDispose(); void BuildBlockRelease(llvm::Value *DeclPtr, int flag = BLOCK_FIELD_IS_BYREF); - bool BlockRequiresCopying(QualType Ty); + bool BlockRequiresCopying(QualType Ty) + { return getContext().BlockRequiresCopying(Ty); } }; } // end namespace CodeGen diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 3960cf51868f..cfa669dc4b6e 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -590,12 +590,15 @@ void CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E) { assert(Dest && "Must have a destination!"); - - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); - if (RD->hasTrivialConstructor()) + const CXXConstructorDecl *CD = E->getConstructor(); + // For a copy constructor, even if it is trivial, must fall thru so + // its argument is code-gen'ed. + if (!CD->isCopyConstructor(getContext())) { + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); + if (RD->hasTrivialConstructor()) return; - + } // Code gen optimization to eliminate copy constructor and return // its first argument instead. if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { @@ -604,7 +607,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, return; } // Call the constructor. - EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest, + EmitCXXConstructorCall(CD, Ctor_Complete, Dest, E->arg_begin(), E->arg_end()); } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index bad166f01ef5..78655168e857 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -639,9 +639,8 @@ 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. - std::string Name = Arg->getNameAsString(); llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(Ty), - (Name + ".addr").c_str()); + Arg->getName() + ".addr"); // FIXME: What are the right qualifiers here? llvm::Function::arg_iterator End = ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI); @@ -650,7 +649,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Name the arguments used in expansion and increment AI. unsigned Index = 0; for (; AI != End; ++AI, ++Index) - AI->setName(Name + "." + llvm::Twine(Index)); + AI->setName(Arg->getName() + "." + llvm::Twine(Index)); continue; } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 4c624205b4ca..1b01e1537b42 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -173,10 +173,14 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT, uint64_t Align = M->getContext().getTypeAlign(BT); uint64_t Offset = 0; - return DebugFactory.CreateBasicType(Unit, - BT->getName(M->getContext().getLangOptions()), - Unit, 0, Size, Align, - Offset, /*flags*/ 0, Encoding); + llvm::DIType DbgTy = + DebugFactory.CreateBasicType(Unit, + BT->getName(M->getContext().getLangOptions()), + Unit, 0, Size, Align, + Offset, /*flags*/ 0, Encoding); + + TypeCache[QualType(BT, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty, @@ -190,9 +194,12 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty, uint64_t Align = M->getContext().getTypeAlign(Ty); uint64_t Offset = 0; - return DebugFactory.CreateBasicType(Unit, "complex", - Unit, 0, Size, Align, - Offset, /*flags*/ 0, Encoding); + llvm::DIType DbgTy = + DebugFactory.CreateBasicType(Unit, "complex", + Unit, 0, Size, Align, + Offset, /*flags*/ 0, Encoding); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } /// CreateCVRType - Get the qualified type from the cache or create @@ -226,8 +233,11 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DICompileUnit U // No need to fill in the Name, Line, Size, Alignment, Offset in case of // CVR derived types. - return DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), - 0, 0, 0, 0, 0, FromTy); + llvm::DIType DbgTy = + DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), + 0, 0, 0, 0, 0, FromTy); + TypeCache[Ty.getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, @@ -238,9 +248,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); - return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, - "", llvm::DICompileUnit(), - 0, Size, Align, 0, 0, EltTy); + llvm::DIType DbgTy = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, + "", llvm::DICompileUnit(), + 0, Size, Align, 0, 0, EltTy); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, @@ -251,9 +264,10 @@ llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); - return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, - "", llvm::DICompileUnit(), - 0, Size, Align, 0, 0, EltTy); + return + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, + "", llvm::DICompileUnit(), + 0, Size, Align, 0, 0, EltTy); } llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, @@ -401,8 +415,11 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); - return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit, - TyName, DefUnit, Line, 0, 0, 0, 0, Src); + llvm::DIType DbgTy = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit, + TyName, DefUnit, Line, 0, 0, 0, 0, Src); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, @@ -424,10 +441,13 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, llvm::DIArray EltTypeArray = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); - return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type, - Unit, "", llvm::DICompileUnit(), - 0, 0, 0, 0, 0, - llvm::DIType(), EltTypeArray); + llvm::DIType DbgTy = + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type, + Unit, "", llvm::DICompileUnit(), + 0, 0, 0, 0, 0, + llvm::DIType(), EltTypeArray); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } /// CreateType - get structure or union type. @@ -713,10 +733,14 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, Align = M->getContext().getTypeAlign(Ty); } - return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, - Unit, EnumName, DefUnit, Line, - Size, Align, 0, 0, - llvm::DIType(), EltArray); + llvm::DIType DbgTy = + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, + Unit, EnumName, DefUnit, Line, + Size, Align, 0, 0, + llvm::DIType(), EltArray); + + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const TagType *Ty, @@ -767,11 +791,15 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DIArray SubscriptArray = DebugFactory.GetOrCreateArray(Subscripts.data(), Subscripts.size()); - return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_array_type, - Unit, "", llvm::DICompileUnit(), - 0, Size, Align, 0, 0, - getOrCreateType(EltTy, Unit), - SubscriptArray); + llvm::DIType DbgTy = + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_array_type, + Unit, "", llvm::DICompileUnit(), + 0, Size, Align, 0, 0, + getOrCreateType(EltTy, Unit), + SubscriptArray); + + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } @@ -793,7 +821,6 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, // Otherwise create the type. llvm::DIType Res = CreateTypeNode(Ty, Unit); - TypeCache.insert(std::make_pair(Ty.getAsOpaquePtr(), Res.getNode())); return Res; } @@ -846,8 +873,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, Unit); case Type::ConstantArray: - case Type::ConstantArrayWithExpr: - case Type::ConstantArrayWithoutExpr: case Type::VariableArray: case Type::IncompleteArray: return CreateType(cast<ArrayType>(Ty), Unit); @@ -863,7 +888,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". -void CGDebugInfo::EmitFunctionStart(const char *Name, QualType ReturnType, +void CGDebugInfo::EmitFunctionStart(const char *Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { const char *LinkageName = Name; @@ -881,7 +906,7 @@ void CGDebugInfo::EmitFunctionStart(const char *Name, QualType ReturnType, llvm::DISubprogram SP = DebugFactory.CreateSubprogram(Unit, Name, Name, LinkageName, Unit, LineNo, - getOrCreateType(ReturnType, Unit), + getOrCreateType(FnType, Unit), Fn->hasInternalLinkage(), true/*definition*/); #ifndef ATTACH_DEBUG_INFO_TO_AN_INSN @@ -1366,7 +1391,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, } DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), - Name, Name, "", Unit, LineNo, + Name, Name, Name, Unit, LineNo, getOrCreateType(T, Unit), Var->hasInternalLinkage(), true/*definition*/, Var); @@ -1396,7 +1421,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, ArrayType::Normal, 0); } - DebugFactory.CreateGlobalVariable(Unit, Name, Name, "", Unit, LineNo, + DebugFactory.CreateGlobalVariable(Unit, Name, Name, Name, Unit, LineNo, getOrCreateType(T, Unit), Var->hasInternalLinkage(), true/*definition*/, Var); diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 0a617b999240..2e44e09d2590 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -88,7 +88,7 @@ public: /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate /// start of a new function. - void EmitFunctionStart(const char *Name, QualType ReturnType, + void EmitFunctionStart(const char *Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder); /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 7feff83dee6b..1728c67292b7 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -37,6 +37,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Enum: // enum X; case Decl::EnumConstant: // enum ? { X = ? } case Decl::CXXRecord: // struct/union/class X; [C++] + case Decl::UsingDirective: // using X; [C++] // None of these decls require codegen support. return; @@ -275,8 +276,8 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) { unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes; if (NumPaddingBytes > 0) { const llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext); - // FIXME: We need a sema error for alignment larger than the minimum of the - // maximal stack alignmint and the alignment of malloc on the system. + // FIXME: We need a sema error for alignment larger than the minimum of + // the maximal stack alignmint and the alignment of malloc on the system. if (NumPaddingBytes > 1) Ty = llvm::ArrayType::get(Ty, NumPaddingBytes); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 01a057f67455..bb487f6e3fdf 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -28,9 +28,9 @@ using namespace CodeGen; /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, - const char *Name) { + const llvm::Twine &Name) { if (!Builder.isNamePreserving()) - Name = ""; + return new llvm::AllocaInst(Ty, 0, "", AllocaInsertPt); return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); } @@ -78,24 +78,18 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, QualType DestType, bool IsInitializer) { + bool ShouldDestroyTemporaries = false; + unsigned OldNumLiveTemporaries = 0; + if (const CXXExprWithTemporaries *TE = dyn_cast<CXXExprWithTemporaries>(E)) { - // If we shouldn't destroy the temporaries, just emit the - // child expression. - if (!TE->shouldDestroyTemporaries()) - return EmitReferenceBindingToExpr(TE->getSubExpr(), DestType, - IsInitializer); - - // Keep track of the current cleanup stack depth. - unsigned OldNumLiveTemporaries = LiveTemporaries.size(); - - RValue RV = EmitReferenceBindingToExpr(TE->getSubExpr(), DestType, - IsInitializer); - - // Pop temporaries. - while (LiveTemporaries.size() > OldNumLiveTemporaries) - PopCXXTemporary(); + ShouldDestroyTemporaries = TE->shouldDestroyTemporaries(); + + if (ShouldDestroyTemporaries) { + // Keep track of the current cleanup stack depth. + OldNumLiveTemporaries = LiveTemporaries.size(); + } - return RV; + E = TE->getSubExpr(); } RValue Val; @@ -105,6 +99,12 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (LV.isSimple()) return RValue::get(LV.getAddress()); Val = EmitLoadOfLValue(LV, E->getType()); + + if (ShouldDestroyTemporaries) { + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + } } else { const CXXRecordDecl *BaseClassDecl = 0; const CXXRecordDecl *DerivedClassDecl = 0; @@ -124,6 +124,12 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, Val = EmitAnyExprToTemp(E, /*IsAggLocVolatile=*/false, IsInitializer); + if (ShouldDestroyTemporaries) { + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + } + if (IsInitializer) { // We might have to destroy the temporary variable. if (const RecordType *RT = E->getType()->getAs<RecordType>()) { @@ -297,6 +303,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: return EmitCastLValue(cast<CastExpr>(E)); + case Expr::CXXZeroInitValueExprClass: + return EmitNullInitializationLValue(cast<CXXZeroInitValueExpr>(E)); } } @@ -858,6 +866,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { llvm::Value *V = LocalDeclMap[IPD]; assert(V && "BlockVarDecl not entered in LocalDeclMap?"); return LValue::MakeAddr(V, MakeQualifiers(E->getType())); + } else if (const QualifiedDeclRefExpr *QDRExpr = + dyn_cast<QualifiedDeclRefExpr>(E)) { + return EmitPointerToDataMemberLValue(QDRExpr); } assert(0 && "Unimp declref"); //an invalid LValue, but the assert will @@ -1307,6 +1318,18 @@ 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; +} + //===--------------------------------------------------------------------===// // Expression Emission //===--------------------------------------------------------------------===// @@ -1356,11 +1379,24 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { return EmitLValue(E->getRHS()); } + if (E->getOpcode() == BinaryOperator::PtrMemD) + return EmitPointerToDataMemberBinaryExpr(E); + // Can only get l-value for binary operator expressions which are a // simple assignment of aggregate type. if (E->getOpcode() != BinaryOperator::Assign) return EmitUnsupportedLValue(E, "binary l-value expression"); + if (!hasAggregateLLVMType(E->getType())) { + // Emit the LHS as an l-value. + LValue LV = EmitLValue(E->getLHS()); + + llvm::Value *RHS = EmitScalarExpr(E->getRHS()); + EmitStoreOfScalar(RHS, LV.getAddress(), LV.isVolatileQualified(), + E->getType()); + return LV; + } + llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); EmitAggExpr(E, Temp, false); // FIXME: Are these qualifiers correct? @@ -1483,6 +1519,25 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { } +LValue CodeGenFunction::EmitPointerToDataMemberLValue( + const QualifiedDeclRefExpr *E) { + const FieldDecl *Field = cast<FieldDecl>(E->getDecl()); + 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, const_cast<FieldDecl*>(Field), + /*isUnion*/false, /*Qualifiers*/0); + const llvm::Type* ResultType = ConvertType( + getContext().getPointerDiffType()); + V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, + "datamember"); + LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); + return LV; +} + RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd, @@ -1492,11 +1547,13 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, assert(CalleeType->isFunctionPointerType() && "Call must have function pointer type!"); - QualType FnType = CalleeType->getAs<PointerType>()->getPointeeType(); - QualType ResultType = FnType->getAs<FunctionType>()->getResultType(); + CalleeType = getContext().getCanonicalType(CalleeType); + + QualType FnType = cast<PointerType>(CalleeType)->getPointeeType(); + QualType ResultType = cast<FunctionType>(FnType)->getResultType(); CallArgList Args; - EmitCallArgs(Args, FnType->getAs<FunctionProtoType>(), ArgBeg, ArgEnd); + EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd); // FIXME: We should not need to do this, it should be part of the function // type. @@ -1508,3 +1565,25 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, CallingConvention), Callee, Args, TargetDecl); } + +LValue CodeGenFunction::EmitPointerToDataMemberBinaryExpr( + const BinaryOperator *E) { + llvm::Value *BaseV = EmitLValue(E->getLHS()).getAddress(); + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(getLLVMContext()); + BaseV = Builder.CreateBitCast(BaseV, i8Ty); + LValue RHSLV = EmitLValue(E->getRHS()); + llvm::Value *OffsetV = + EmitLoadOfLValue(RHSLV, E->getRHS()->getType()).getScalarVal(); + const llvm::Type* ResultType = ConvertType(getContext().getPointerDiffType()); + OffsetV = Builder.CreateBitCast(OffsetV, ResultType); + llvm::Value *AddV = Builder.CreateInBoundsGEP(BaseV, OffsetV, "add.ptr"); + QualType Ty = E->getRHS()->getType(); + const MemberPointerType *MemPtrType = Ty->getAs<MemberPointerType>(); + Ty = MemPtrType->getPointeeType(); + const llvm::Type* PType = + ConvertType(getContext().getPointerType(Ty)); + AddV = Builder.CreateBitCast(AddV, PType); + LValue LV = LValue::MakeAddr(AddV, MakeQualifiers(Ty)); + return LV; +} + diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 0866ff893c4e..f47b6ab3c8cc 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -92,6 +92,7 @@ public: void VisitCallExpr(const CallExpr *E); void VisitStmtExpr(const StmtExpr *E); void VisitBinaryOperator(const BinaryOperator *BO); + void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *BO); void VisitBinAssign(const BinaryOperator *E); void VisitBinComma(const BinaryOperator *E); void VisitUnaryAddrOf(const UnaryOperator *E); @@ -112,6 +113,7 @@ public: void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); void VisitCXXConstructExpr(const CXXConstructExpr *E); void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E); + void VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); void VisitVAArgExpr(VAArgExpr *E); @@ -214,6 +216,12 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { break; } + case CastExpr::CK_BitCast: { + // This must be a member function pointer cast. + Visit(E->getSubExpr()); + break; + } + case CastExpr::CK_BaseToDerivedMemberPointer: { QualType SrcType = E->getSubExpr()->getType(); @@ -285,6 +293,7 @@ void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { // We have a member function pointer. const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>(); + (void) MPT; assert(MPT->getPointeeType()->isFunctionProtoType() && "Unexpected member pointer type!"); @@ -320,7 +329,16 @@ void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { } void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) { - CGF.ErrorUnsupported(E, "aggregate binary expression"); + if (E->getOpcode() == BinaryOperator::PtrMemD) + VisitPointerToDataMemberBinaryOperator(E); + else + CGF.ErrorUnsupported(E, "aggregate binary expression"); +} + +void AggExprEmitter::VisitPointerToDataMemberBinaryOperator( + const BinaryOperator *E) { + LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(E); + EmitFinalDestCopy(E, LV); } void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { @@ -438,6 +456,11 @@ void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { CGF.EmitCXXExprWithTemporaries(E, DestPtr, VolatileDest, IsInitializer); } +void AggExprEmitter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { + LValue lvalue = LValue::MakeAddr(DestPtr, Qualifiers()); + EmitNullInitializationToLValue(lvalue, E->getType()); +} + void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) { // FIXME: Ignore result? // FIXME: Are initializers affected by volatile? diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 7f540c3c0688..fc3748c8e3c8 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -542,7 +542,11 @@ public: return CS; } } - + + case CastExpr::CK_BitCast: + // This must be a member function pointer cast. + return Visit(E->getSubExpr()); + default: { // FIXME: This should be handled by the CK_NoOp cast kind. // Explicit and implicit no-op casts diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index cc81256032af..69604f9aaaee 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -106,6 +106,7 @@ public: return 0; } Value *VisitExpr(Expr *S); + Value *VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); } // Leaves. @@ -181,48 +182,7 @@ public: Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); } - Value *VisitInitListExpr(InitListExpr *E) { - bool Ignore = TestAndClearIgnoreResultAssign(); - (void)Ignore; - assert (Ignore == false && "init list ignored"); - unsigned NumInitElements = E->getNumInits(); - - if (E->hadArrayRangeDesignator()) { - CGF.ErrorUnsupported(E, "GNU array range designator extension"); - } - - const llvm::VectorType *VType = - dyn_cast<llvm::VectorType>(ConvertType(E->getType())); - - // We have a scalar in braces. Just use the first element. - if (!VType) - return Visit(E->getInit(0)); - - unsigned NumVectorElements = VType->getNumElements(); - const llvm::Type *ElementType = VType->getElementType(); - - // Emit individual vector element stores. - llvm::Value *V = llvm::UndefValue::get(VType); - - // Emit initializers - unsigned i; - for (i = 0; i < NumInitElements; ++i) { - Value *NewV = Visit(E->getInit(i)); - Value *Idx = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), i); - V = Builder.CreateInsertElement(V, NewV, Idx); - } - - // Emit remaining default initializers - for (/* Do not initialize i*/; i < NumVectorElements; ++i) { - Value *Idx = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), i); - llvm::Value *NewV = llvm::Constant::getNullValue(ElementType); - V = Builder.CreateInsertElement(V, NewV, Idx); - } - - return V; - } + Value *VisitInitListExpr(InitListExpr *E); Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { return llvm::Constant::getNullValue(ConvertType(E->getType())); @@ -404,7 +364,7 @@ public: /// EmitConversionToBool - Convert the specified expression value to a /// boolean (i1) truth value. This is equivalent to "Val != 0". Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { - assert(SrcType->isCanonical() && "EmitScalarConversion strips typedefs"); + assert(SrcType.isCanonical() && "EmitScalarConversion strips typedefs"); if (SrcType->isRealFloatingType()) { // Compare against 0.0 for fp scalars. @@ -577,6 +537,13 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, //===----------------------------------------------------------------------===// Value *ScalarExprEmitter::VisitExpr(Expr *E) { + if (const BinaryOperator *BExpr = dyn_cast<BinaryOperator>(E)) + if (BExpr->getOpcode() == BinaryOperator::PtrMemD) { + LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(BExpr); + Value *InVal = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal(); + return InVal; + } + CGF.ErrorUnsupported(E, "scalar expression"); if (E->getType()->isVoidType()) return 0; @@ -616,6 +583,174 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { return Builder.CreateExtractElement(Base, Idx, "vecext"); } +static llvm::Constant *getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx, + unsigned Off, const llvm::Type *I32Ty) { + int MV = SVI->getMaskValue(Idx); + if (MV == -1) + return llvm::UndefValue::get(I32Ty); + return llvm::ConstantInt::get(I32Ty, Off+MV); +} + +Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { + bool Ignore = TestAndClearIgnoreResultAssign(); + (void)Ignore; + assert (Ignore == false && "init list ignored"); + unsigned NumInitElements = E->getNumInits(); + + if (E->hadArrayRangeDesignator()) + CGF.ErrorUnsupported(E, "GNU array range designator extension"); + + const llvm::VectorType *VType = + dyn_cast<llvm::VectorType>(ConvertType(E->getType())); + + // We have a scalar in braces. Just use the first element. + if (!VType) + return Visit(E->getInit(0)); + + unsigned ResElts = VType->getNumElements(); + const llvm::Type *I32Ty = llvm::Type::getInt32Ty(CGF.getLLVMContext()); + + // Loop over initializers collecting the Value for each, and remembering + // whether the source was swizzle (ExtVectorElementExpr). This will allow + // us to fold the shuffle for the swizzle into the shuffle for the vector + // initializer, since LLVM optimizers generally do not want to touch + // shuffles. + unsigned CurIdx = 0; + bool VIsUndefShuffle = false; + llvm::Value *V = llvm::UndefValue::get(VType); + for (unsigned i = 0; i != NumInitElements; ++i) { + Expr *IE = E->getInit(i); + Value *Init = Visit(IE); + llvm::SmallVector<llvm::Constant*, 16> Args; + + const llvm::VectorType *VVT = dyn_cast<llvm::VectorType>(Init->getType()); + + // Handle scalar elements. If the scalar initializer is actually one + // element of a different vector of the same width, use shuffle instead of + // extract+insert. + if (!VVT) { + if (isa<ExtVectorElementExpr>(IE)) { + llvm::ExtractElementInst *EI = cast<llvm::ExtractElementInst>(Init); + + if (EI->getVectorOperandType()->getNumElements() == ResElts) { + llvm::ConstantInt *C = cast<llvm::ConstantInt>(EI->getIndexOperand()); + Value *LHS = 0, *RHS = 0; + if (CurIdx == 0) { + // insert into undef -> shuffle (src, undef) + Args.push_back(C); + for (unsigned j = 1; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + + LHS = EI->getVectorOperand(); + RHS = V; + VIsUndefShuffle = true; + } else if (VIsUndefShuffle) { + // insert into undefshuffle && size match -> shuffle (v, src) + llvm::ShuffleVectorInst *SVV = cast<llvm::ShuffleVectorInst>(V); + for (unsigned j = 0; j != CurIdx; ++j) + Args.push_back(getMaskElt(SVV, j, 0, I32Ty)); + Args.push_back(llvm::ConstantInt::get(I32Ty, + ResElts + C->getZExtValue())); + for (unsigned j = CurIdx + 1; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + + LHS = cast<llvm::ShuffleVectorInst>(V)->getOperand(0); + RHS = EI->getVectorOperand(); + VIsUndefShuffle = false; + } + if (!Args.empty()) { + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], ResElts); + V = Builder.CreateShuffleVector(LHS, RHS, Mask); + ++CurIdx; + continue; + } + } + } + Value *Idx = llvm::ConstantInt::get(I32Ty, CurIdx); + V = Builder.CreateInsertElement(V, Init, Idx, "vecinit"); + VIsUndefShuffle = false; + ++CurIdx; + continue; + } + + unsigned InitElts = VVT->getNumElements(); + + // If the initializer is an ExtVecEltExpr (a swizzle), and the swizzle's + // input is the same width as the vector being constructed, generate an + // optimized shuffle of the swizzle input into the result. + if (isa<ExtVectorElementExpr>(IE)) { + llvm::ShuffleVectorInst *SVI = cast<llvm::ShuffleVectorInst>(Init); + Value *SVOp = SVI->getOperand(0); + const llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType()); + + if (OpTy->getNumElements() == ResElts) { + unsigned Offset = (CurIdx == 0) ? 0 : ResElts; + + for (unsigned j = 0; j != CurIdx; ++j) { + // If the current vector initializer is a shuffle with undef, merge + // this shuffle directly into it. + if (VIsUndefShuffle) { + Args.push_back(getMaskElt(cast<llvm::ShuffleVectorInst>(V), j, 0, + I32Ty)); + } else { + Args.push_back(llvm::ConstantInt::get(I32Ty, j)); + } + } + for (unsigned j = 0, je = InitElts; j != je; ++j) + Args.push_back(getMaskElt(SVI, j, Offset, I32Ty)); + for (unsigned j = CurIdx + InitElts; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + + if (VIsUndefShuffle) + V = cast<llvm::ShuffleVectorInst>(V)->getOperand(0); + + Init = SVOp; + } + } + + // Extend init to result vector length, and then shuffle its contribution + // to the vector initializer into V. + if (Args.empty()) { + for (unsigned j = 0; j != InitElts; ++j) + Args.push_back(llvm::ConstantInt::get(I32Ty, j)); + for (unsigned j = InitElts; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], ResElts); + Init = Builder.CreateShuffleVector(Init, llvm::UndefValue::get(VVT), + Mask, "vecext"); + + Args.clear(); + for (unsigned j = 0; j != CurIdx; ++j) + Args.push_back(llvm::ConstantInt::get(I32Ty, j)); + for (unsigned j = 0; j != InitElts; ++j) + Args.push_back(llvm::ConstantInt::get(I32Ty, j+ResElts)); + for (unsigned j = CurIdx + InitElts; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + } + + // If V is undef, make sure it ends up on the RHS of the shuffle to aid + // merging subsequent shuffles into this one. + if (CurIdx == 0) + std::swap(V, Init); + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], ResElts); + V = Builder.CreateShuffleVector(V, Init, Mask, "vecinit"); + VIsUndefShuffle = isa<llvm::UndefValue>(Init); + CurIdx += InitElts; + } + + // FIXME: evaluate codegen vs. shuffling against constant null vector. + // Emit remaining default initializers. + const llvm::Type *EltTy = VType->getElementType(); + + // Emit remaining default initializers + for (/* Do not initialize i*/; CurIdx < ResElts; ++CurIdx) { + Value *Idx = llvm::ConstantInt::get(I32Ty, CurIdx); + llvm::Value *Init = llvm::Constant::getNullValue(EltTy); + V = Builder.CreateInsertElement(V, Init, Idx, "vecinit"); + } + return V; +} + // VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts // have to handle a more broad range of conversions than explicit casts, as they // handle things like function to ptr-to-function decay etc. @@ -700,7 +835,16 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { case CastExpr::CK_IntegralToPointer: { Value *Src = Visit(const_cast<Expr*>(E)); - return Builder.CreateIntToPtr(Src, ConvertType(DestTy)); + + // First, convert to the correct width so that we control the kind of + // extension. + const llvm::Type *MiddleTy = + llvm::IntegerType::get(VMContext, CGF.LLVMPointerWidth); + bool InputSigned = E->getType()->isSignedIntegerType(); + llvm::Value* IntResult = + Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); + + return Builder.CreateIntToPtr(IntResult, ConvertType(DestTy)); } case CastExpr::CK_PointerToIntegral: { @@ -1379,18 +1523,20 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { } Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { + const llvm::Type *ResTy = ConvertType(E->getType()); + // If we have 0 && RHS, see if we can elide RHS, if so, just return 0. // If we have 1 && X, just emit X without inserting the control flow. if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) { if (Cond == 1) { // If we have 1 && X, just emit X. Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - // ZExt result to int. - return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "land.ext"); + // ZExt result to int or bool. + return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext"); } - // 0 && RHS: If it is safe, just elide the RHS, and return 0. + // 0 && RHS: If it is safe, just elide the RHS, and return 0/false. if (!CGF.ContainsLabel(E->getRHS())) - return llvm::Constant::getNullValue(CGF.LLVMIntTy); + return llvm::Constant::getNullValue(ResTy); } llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end"); @@ -1423,22 +1569,24 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { PN->addIncoming(RHSCond, RHSBlock); // ZExt result to int. - return Builder.CreateZExt(PN, CGF.LLVMIntTy, "land.ext"); + return Builder.CreateZExtOrBitCast(PN, ResTy, "land.ext"); } Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { + const llvm::Type *ResTy = ConvertType(E->getType()); + // If we have 1 || RHS, see if we can elide RHS, if so, just return 1. // If we have 0 || X, just emit X without inserting the control flow. if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) { if (Cond == -1) { // If we have 0 || X, just emit X. Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - // ZExt result to int. - return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "lor.ext"); + // ZExt result to int or bool. + return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext"); } - // 1 || RHS: If it is safe, just elide the RHS, and return 1. + // 1 || RHS: If it is safe, just elide the RHS, and return 1/true. if (!CGF.ContainsLabel(E->getRHS())) - return llvm::ConstantInt::get(CGF.LLVMIntTy, 1); + return llvm::ConstantInt::get(ResTy, 1); } llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end"); @@ -1474,7 +1622,7 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { PN->addIncoming(RHSCond, RHSBlock); // ZExt result to int. - return Builder.CreateZExt(PN, CGF.LLVMIntTy, "lor.ext"); + return Builder.CreateZExtOrBitCast(PN, ResTy, "lor.ext"); } Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) { diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 4485ed5aee75..9b2f4a1faee7 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -850,7 +850,7 @@ protected: /// \param[out] NameOut - The return value. void GetNameForMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD, - std::string &NameOut); + llvm::SmallVectorImpl<char> &NameOut); /// GetMethodVarName - Return a unique constant for the given /// selector's name. The return value has type char *. @@ -900,7 +900,7 @@ protected: /// EmitPropertyList - Emit the given property list. The return /// value has type PropertyListPtrTy. - llvm::Constant *EmitPropertyList(const std::string &Name, + llvm::Constant *EmitPropertyList(llvm::Twine Name, const Decl *Container, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes); @@ -924,7 +924,7 @@ protected: /// \param Align - The alignment for the variable, or 0. /// \param AddToUsed - Whether the variable should be added to /// "llvm.used". - llvm::GlobalVariable *CreateMetadataVar(const std::string &Name, + llvm::GlobalVariable *CreateMetadataVar(llvm::Twine Name, llvm::Constant *Init, const char *Section, unsigned Align, @@ -1025,7 +1025,7 @@ private: /// EmitMethodList - Emit the method list for the given /// implementation. The return value has type MethodListPtrTy. - llvm::Constant *EmitMethodList(const std::string &Name, + llvm::Constant *EmitMethodList(llvm::Twine Name, const char *Section, const ConstantVector &Methods); @@ -1040,7 +1040,7 @@ private: /// - begin, end: The method list to output. /// /// The return value has type MethodDescriptionListPtrTy. - llvm::Constant *EmitMethodDescList(const std::string &Name, + llvm::Constant *EmitMethodDescList(llvm::Twine Name, const char *Section, const ConstantVector &Methods); @@ -1066,7 +1066,7 @@ private: /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. - llvm::Constant *EmitProtocolList(const std::string &Name, + llvm::Constant *EmitProtocolList(llvm::Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end); @@ -1197,7 +1197,7 @@ private: /// EmitMethodList - Emit the method list for the given /// implementation. The return value has type MethodListnfABITy. - llvm::Constant *EmitMethodList(const std::string &Name, + llvm::Constant *EmitMethodList(llvm::Twine Name, const char *Section, const ConstantVector &Methods); /// EmitIvarList - Emit the ivar list for the given @@ -1224,7 +1224,7 @@ private: /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. - llvm::Constant *EmitProtocolList(const std::string &Name, + llvm::Constant *EmitProtocolList(llvm::Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end); @@ -1616,8 +1616,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { // resolved. Investigate. Its also wasteful to look this up over and over. LazySymbols.insert(&CGM.getContext().Idents.get("Protocol")); - const char *ProtocolName = PD->getNameAsCString(); - // Construct method lists. std::vector<llvm::Constant*> InstanceMethods, ClassMethods; std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods; @@ -1647,17 +1645,15 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { Values[0] = EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods); Values[1] = GetClassName(PD->getIdentifier()); Values[2] = - EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getNameAsString(), + EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getName(), PD->protocol_begin(), PD->protocol_end()); Values[3] = - EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_" - + PD->getNameAsString(), + EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_" + PD->getName(), "__OBJC,__cat_inst_meth,regular,no_dead_strip", InstanceMethods); Values[4] = - EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" - + PD->getNameAsString(), + EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" + PD->getName(), "__OBJC,__cat_cls_meth,regular,no_dead_strip", ClassMethods); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy, @@ -1672,7 +1668,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false, llvm::GlobalValue::InternalLinkage, Init, - std::string("\01L_OBJC_PROTOCOL_")+ProtocolName); + "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? @@ -1694,7 +1690,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) { new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false, llvm::GlobalValue::ExternalLinkage, 0, - "\01L_OBJC_PROTOCOL_" + PD->getNameAsString()); + "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? @@ -1722,16 +1718,14 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); Values[1] = EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_" - + PD->getNameAsString(), + + PD->getName(), "__OBJC,__cat_inst_meth,regular,no_dead_strip", OptInstanceMethods); Values[2] = - EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_" - + PD->getNameAsString(), + EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_" + PD->getName(), "__OBJC,__cat_cls_meth,regular,no_dead_strip", OptClassMethods); - Values[3] = EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + - PD->getNameAsString(), + Values[3] = EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + PD->getName(), 0, PD, ObjCTypes); // Return null if no extension bits are used. @@ -1743,7 +1737,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, llvm::ConstantStruct::get(ObjCTypes.ProtocolExtensionTy, Values); // No special section, but goes in llvm.used - return CreateMetadataVar("\01L_OBJC_PROTOCOLEXT_" + PD->getNameAsString(), + return CreateMetadataVar("\01L_OBJC_PROTOCOLEXT_" + PD->getName(), Init, 0, 0, true); } @@ -1756,7 +1750,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, }; */ llvm::Constant * -CGObjCMac::EmitProtocolList(const std::string &Name, +CGObjCMac::EmitProtocolList(llvm::Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end) { std::vector<llvm::Constant*> ProtocolRefs; @@ -1800,7 +1794,7 @@ CGObjCMac::EmitProtocolList(const std::string &Name, struct _objc_property[prop_count]; }; */ -llvm::Constant *CGObjCCommonMac::EmitPropertyList(const std::string &Name, +llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name, const Decl *Container, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes) { @@ -1854,7 +1848,7 @@ CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { Desc); } -llvm::Constant *CGObjCMac::EmitMethodDescList(const std::string &Name, +llvm::Constant *CGObjCMac::EmitMethodDescList(llvm::Twine Name, const char *Section, const ConstantVector &Methods) { // Return null for empty list. @@ -1894,8 +1888,10 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { const ObjCInterfaceDecl *Interface = OCD->getClassInterface(); const ObjCCategoryDecl *Category = Interface->FindCategoryDeclaration(OCD->getIdentifier()); - std::string ExtName(Interface->getNameAsString() + "_" + - OCD->getNameAsString()); + + llvm::SmallString<256> ExtName; + llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_' + << OCD->getName(); std::vector<llvm::Constant*> InstanceMethods, ClassMethods; for (ObjCCategoryImplDecl::instmeth_iterator @@ -1914,17 +1910,16 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values[1] = GetClassName(Interface->getIdentifier()); LazySymbols.insert(Interface->getIdentifier()); Values[2] = - EmitMethodList(std::string("\01L_OBJC_CATEGORY_INSTANCE_METHODS_") + - ExtName, + EmitMethodList("\01L_OBJC_CATEGORY_INSTANCE_METHODS_" + ExtName.str(), "__OBJC,__cat_inst_meth,regular,no_dead_strip", InstanceMethods); Values[3] = - EmitMethodList(std::string("\01L_OBJC_CATEGORY_CLASS_METHODS_") + ExtName, + EmitMethodList("\01L_OBJC_CATEGORY_CLASS_METHODS_" + ExtName.str(), "__OBJC,__cat_cls_meth,regular,no_dead_strip", ClassMethods); if (Category) { Values[4] = - EmitProtocolList(std::string("\01L_OBJC_CATEGORY_PROTOCOLS_") + ExtName, + EmitProtocolList("\01L_OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(), Category->protocol_begin(), Category->protocol_end()); } else { @@ -1934,7 +1929,7 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { // If there is no category @interface then there can be no properties. if (Category) { - Values[6] = EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_")+ExtName, + Values[6] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(), OCD, Category, ObjCTypes); } else { Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); @@ -1944,7 +1939,7 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values); llvm::GlobalVariable *GV = - CreateMetadataVar(std::string("\01L_OBJC_CATEGORY_")+ExtName, Init, + CreateMetadataVar("\01L_OBJC_CATEGORY_" + ExtName.str(), Init, "__OBJC,__category,regular,no_dead_strip", 4, true); DefinedCategories.push_back(GV); @@ -1988,7 +1983,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { ObjCInterfaceDecl *Interface = const_cast<ObjCInterfaceDecl*>(ID->getClassInterface()); llvm::Constant *Protocols = - EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getNameAsString(), + EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(), Interface->protocol_begin(), Interface->protocol_end()); unsigned Flags = eClassFlags_Factory; @@ -2046,7 +2041,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size); Values[ 6] = EmitIvarList(ID, false); Values[ 7] = - EmitMethodList("\01L_OBJC_INSTANCE_METHODS_" + ID->getNameAsString(), + EmitMethodList("\01L_OBJC_INSTANCE_METHODS_" + ID->getName(), "__OBJC,__inst_meth,regular,no_dead_strip", InstanceMethods); // cache is always NULL. @@ -2058,7 +2053,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Values); llvm::GlobalVariable *GV = - CreateMetadataVar(std::string("\01L_OBJC_CLASS_")+ClassName, Init, + CreateMetadataVar("\01L_OBJC_CLASS_" + ClassName, Init, "__OBJC,__class,regular,no_dead_strip", 4, true); DefinedClasses.push_back(GV); @@ -2174,7 +2169,7 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) { std::vector<llvm::Constant*> Values(3); Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); Values[1] = BuildIvarLayout(ID, false); - Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getNameAsString(), + Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(), ID, ID->getClassInterface(), ObjCTypes); // Return null if no extension bits are used. @@ -2183,7 +2178,7 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) { llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values); - return CreateMetadataVar("\01L_OBJC_CLASSEXT_" + ID->getNameAsString(), + return CreateMetadataVar("\01L_OBJC_CLASSEXT_" + ID->getName(), Init, "__OBJC,__class_ext,regular,no_dead_strip", 4, true); } @@ -2243,12 +2238,11 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, llvm::GlobalVariable *GV; if (ForClass) - GV = CreateMetadataVar("\01L_OBJC_CLASS_VARIABLES_" + ID->getNameAsString(), + GV = CreateMetadataVar("\01L_OBJC_CLASS_VARIABLES_" + ID->getName(), Init, "__OBJC,__class_vars,regular,no_dead_strip", 4, true); else - GV = CreateMetadataVar("\01L_OBJC_INSTANCE_VARIABLES_" - + ID->getNameAsString(), + GV = CreateMetadataVar("\01L_OBJC_INSTANCE_VARIABLES_" + ID->getName(), Init, "__OBJC,__instance_vars,regular,no_dead_strip", 4, true); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy); @@ -2286,7 +2280,7 @@ llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) { return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method); } -llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name, +llvm::Constant *CGObjCMac::EmitMethodList(llvm::Twine Name, const char *Section, const ConstantVector &Methods) { // Return null for empty list. @@ -2308,7 +2302,7 @@ llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name, llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { - std::string Name; + llvm::SmallString<256> Name; GetNameForMethod(OMD, CD, Name); CodeGenTypes &Types = CGM.getTypes(); @@ -2317,7 +2311,7 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, llvm::Function *Method = llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage, - Name, + Name.str(), &CGM.getModule()); MethodDefinitions.insert(std::make_pair(OMD, Method)); @@ -2325,7 +2319,7 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, } llvm::GlobalVariable * -CGObjCCommonMac::CreateMetadataVar(const std::string &Name, +CGObjCCommonMac::CreateMetadataVar(llvm::Twine Name, llvm::Constant *Init, const char *Section, unsigned Align, @@ -2985,7 +2979,8 @@ llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) { if (!Entry) Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_", - llvm::ConstantArray::get(VMContext, Ident->getName()), + llvm::ConstantArray::get(VMContext, + Ident->getNameStart()), "__TEXT,__cstring,cstring_literals", 1, true); @@ -3434,7 +3429,8 @@ llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) { if (!Entry) Entry = CreateMetadataVar("\01L_OBJC_PROP_NAME_ATTR_", - llvm::ConstantArray::get(VMContext, Ident->getName()), + llvm::ConstantArray::get(VMContext, + Ident->getNameStart()), "__TEXT,__cstring,cstring_literals", 1, true); @@ -3453,21 +3449,15 @@ CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD, void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, const ObjCContainerDecl *CD, - std::string &NameOut) { - NameOut = '\01'; - NameOut += (D->isInstanceMethod() ? '-' : '+'); - NameOut += '['; + llvm::SmallVectorImpl<char> &Name) { + llvm::raw_svector_ostream OS(Name); assert (CD && "Missing container decl in GetNameForMethod"); - NameOut += CD->getNameAsString(); + OS << '\01' << (D->isInstanceMethod() ? '-' : '+') + << '[' << CD->getName(); if (const ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext())) { - NameOut += '('; - NameOut += CID->getNameAsString(); - NameOut+= ')'; - } - NameOut += ' '; - NameOut += D->getSelector().getAsString(); - NameOut += ']'; + dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext())) + OS << '(' << CID->getNameAsString() << ')'; + OS << ' ' << D->getSelector().getAsString() << ']'; } void CGObjCMac::FinishModule() { @@ -4256,7 +4246,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( const ObjCInterfaceDecl *OID = ID->getClassInterface(); assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer"); Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_" - + OID->getNameAsString(), + + OID->getName(), OID->protocol_begin(), OID->protocol_end()); @@ -4269,9 +4259,8 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( if (flags & CLS_META) Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); else - Values[ 9] = - EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getNameAsString(), - ID, ID->getClassInterface(), ObjCTypes); + Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(), + ID, ID->getClassInterface(), ObjCTypes); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy, Values); llvm::GlobalVariable *CLASS_RO_GV = @@ -4532,16 +4521,16 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { const ObjCCategoryDecl *Category = Interface->FindCategoryDeclaration(OCD->getIdentifier()); if (Category) { - std::string ExtName(Interface->getNameAsString() + "_$_" + - OCD->getNameAsString()); + llvm::SmallString<256> ExtName; + llvm::raw_svector_ostream(ExtName) << Interface->getName() << "_$_" + << OCD->getName(); Values[4] = EmitProtocolList("\01l_OBJC_CATEGORY_PROTOCOLS_$_" - + Interface->getNameAsString() + "_$_" - + Category->getNameAsString(), + + Interface->getName() + "_$_" + + Category->getName(), Category->protocol_begin(), Category->protocol_end()); - Values[5] = - EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_") + ExtName, - OCD, Category, ObjCTypes); + Values[5] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(), + OCD, Category, ObjCTypes); } else { Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy); Values[5] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); @@ -4593,10 +4582,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant( /// struct _objc_method method_list[method_count]; /// } /// -llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList( - const std::string &Name, - const char *Section, - const ConstantVector &Methods) { +llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name, + const char *Section, + const ConstantVector &Methods) { // Return null for empty list. if (Methods.empty()) return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy); @@ -4742,7 +4730,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, llvm::GlobalValue::InternalLinkage, Init, - Prefix + OID->getNameAsString()); + Prefix + OID->getName()); GV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(Init->getType())); GV->setSection("__DATA, __objc_const"); @@ -4763,7 +4751,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef( new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false, llvm::GlobalValue::ExternalLinkage, 0, - "\01l_OBJC_PROTOCOL_$_" + PD->getNameAsString()); + "\01l_OBJC_PROTOCOL_$_" + PD->getName()); Entry->setSection("__DATA,__datacoal_nt,coalesced"); } @@ -4795,8 +4783,6 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( if (Entry && Entry->hasInitializer()) return Entry; - const char *ProtocolName = PD->getNameAsCString(); - // Construct method lists. std::vector<llvm::Constant*> InstanceMethods, ClassMethods; std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods; @@ -4826,28 +4812,27 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( // isa is NULL Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy); Values[1] = GetClassName(PD->getIdentifier()); - Values[2] = EmitProtocolList( - "\01l_OBJC_$_PROTOCOL_REFS_" + PD->getNameAsString(), - PD->protocol_begin(), - PD->protocol_end()); + Values[2] = EmitProtocolList("\01l_OBJC_$_PROTOCOL_REFS_" + PD->getName(), + PD->protocol_begin(), + PD->protocol_end()); Values[3] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_" - + PD->getNameAsString(), + + PD->getName(), "__DATA, __objc_const", InstanceMethods); Values[4] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_" - + PD->getNameAsString(), + + PD->getName(), "__DATA, __objc_const", ClassMethods); Values[5] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_" - + PD->getNameAsString(), + + PD->getName(), "__DATA, __objc_const", OptInstanceMethods); Values[6] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_" - + PD->getNameAsString(), + + PD->getName(), "__DATA, __objc_const", OptClassMethods); - Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getNameAsString(), + Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getName(), 0, PD, ObjCTypes); uint32_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy); @@ -4862,10 +4847,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( Entry->setInitializer(Init); } else { Entry = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false, - llvm::GlobalValue::WeakAnyLinkage, - Init, - std::string("\01l_OBJC_PROTOCOL_$_")+ProtocolName); + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, + false, llvm::GlobalValue::WeakAnyLinkage, Init, + "\01l_OBJC_PROTOCOL_$_" + PD->getName()); Entry->setAlignment( CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy)); Entry->setSection("__DATA,__datacoal_nt,coalesced"); @@ -4875,13 +4859,10 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( // Use this protocol meta-data to build protocol list table in section // __DATA, __objc_protolist - llvm::GlobalVariable *PTGV = new llvm::GlobalVariable( - CGM.getModule(), - ObjCTypes.ProtocolnfABIPtrTy, false, - llvm::GlobalValue::WeakAnyLinkage, - Entry, - std::string("\01l_OBJC_LABEL_PROTOCOL_$_") - +ProtocolName); + llvm::GlobalVariable *PTGV = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABIPtrTy, + false, llvm::GlobalValue::WeakAnyLinkage, Entry, + "\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName()); PTGV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip"); @@ -4899,9 +4880,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( /// @endcode /// llvm::Constant * -CGObjCNonFragileABIMac::EmitProtocolList(const std::string &Name, - ObjCProtocolDecl::protocol_iterator begin, - ObjCProtocolDecl::protocol_iterator end) { +CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name, + ObjCProtocolDecl::protocol_iterator begin, + ObjCProtocolDecl::protocol_iterator end) { std::vector<llvm::Constant*> ProtocolRefs; // Just return null for empty protocol lists @@ -4909,10 +4890,12 @@ CGObjCNonFragileABIMac::EmitProtocolList(const std::string &Name, return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy); // FIXME: We shouldn't need to do this lookup here, should we? - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true); + llvm::SmallString<256> TmpName; + Name.toVector(TmpName); + llvm::GlobalVariable *GV = + CGM.getModule().getGlobalVariable(TmpName.str(), true); if (GV) - return llvm::ConstantExpr::getBitCast(GV, - ObjCTypes.ProtocolListnfABIPtrTy); + return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); for (; begin != end; ++begin) ProtocolRefs.push_back(GetProtocolRef(*begin)); // Implemented??? @@ -5683,7 +5666,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false, llvm::GlobalValue::ExternalLinkage, 0, - (std::string("OBJC_EHTYPE_$_") + + ("OBJC_EHTYPE_$_" + ID->getIdentifier()->getName())); } @@ -5715,7 +5698,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false, llvm::GlobalValue::WeakAnyLinkage, Init, - (std::string("OBJC_EHTYPE_$_") + + ("OBJC_EHTYPE_$_" + ID->getIdentifier()->getName())); } diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 6e73db359af1..9df0e1abd547 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -119,6 +119,43 @@ public: Index_t VBlookup(CXXRecordDecl *D, CXXRecordDecl *B); + Index_t getNVOffset_1(const CXXRecordDecl *D, const CXXRecordDecl *B, + Index_t Offset = 0) { + + if (B == D) + return Offset; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(D); + for (CXXRecordDecl::base_class_const_iterator i = D->bases_begin(), + e = D->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + int64_t BaseOffset = 0; + if (!i->isVirtual()) + BaseOffset = Offset + Layout.getBaseClassOffset(Base); + int64_t o = getNVOffset_1(Base, B, BaseOffset); + if (o >= 0) + return o; + } + + return -1; + } + + /// getNVOffset - Returns the non-virtual offset for the given (B) base of the + /// derived class D. + Index_t getNVOffset(QualType qB, QualType qD) { + qD = qD->getAs<PointerType>()->getPointeeType(); + qB = qB->getAs<PointerType>()->getPointeeType(); + CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); + CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); + int64_t o = getNVOffset_1(D, B); + if (o >= 0) + return o; + + assert(false && "FIXME: non-virtual base not found"); + return 0; + } + /// getVbaseOffset - Returns the index into the vtable for the virtual base /// offset for the given (B) virtual base of the derived class D. Index_t getVbaseOffset(QualType qB, QualType qD) { @@ -138,8 +175,10 @@ public: } bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m, - bool MorallyVirtual, Index_t Offset) { + bool MorallyVirtual, Index_t OverrideOffset, + Index_t Offset) { typedef CXXMethodDecl::method_iterator meth_iter; + // FIXME: Should OverrideOffset's be Offset? // FIXME: Don't like the nested loops. For very large inheritance // heirarchies we could have a table on the side with the final overridder @@ -166,11 +205,12 @@ public: CallOffset ReturnOffset = std::make_pair(0, 0); if (oret != ret) { // FIXME: calculate offsets for covariance - Index_t nv = 0; if (CovariantThunks.count(OMD)) { oret = CovariantThunks[OMD].second; CovariantThunks.erase(OMD); } + // FIXME: Double check oret + Index_t nv = getNVOffset(oret, ret)/8; ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret)); } Index[MD] = i; @@ -180,17 +220,16 @@ public: if (MorallyVirtual) { Index_t &idx = VCall[OMD]; if (idx == 0) { - VCallOffset[MD] = Offset/8; + VCallOffset[MD] = OverrideOffset/8; idx = VCalls.size()+1; VCalls.push_back(0); } else { VCallOffset[MD] = VCallOffset[OMD]; - VCalls[idx-1] = -VCallOffset[OMD] + Offset/8; + VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8; } VCall[MD] = idx; CallOffset ThisOffset; - // FIXME: calculate non-virtual offset - ThisOffset = std::make_pair(0 /* -CurrentVBaseOffset/8 + Offset/8 */, + ThisOffset = std::make_pair(CurrentVBaseOffset/8 - Offset/8, -((idx+extra+2)*LLVMPointerWidth/8)); // FIXME: Do we always have to build a covariant thunk to save oret, // which is the containing virtual base class? @@ -204,8 +243,8 @@ public: } // FIXME: finish off - int64_t O = VCallOffset[OMD] - Offset/8; - // int64_t O = CurrentVBaseOffset/8 - Offset/8; + int64_t O = VCallOffset[OMD] - OverrideOffset/8; + // int64_t O = CurrentVBaseOffset/8 - OverrideOffset/8; if (O || ReturnOffset.first || ReturnOffset.second) { CallOffset ThisOffset = std::make_pair(O, 0); @@ -248,11 +287,11 @@ public: CovariantThunks.clear(); } - void OverrideMethods(Path_t *Path, bool MorallyVirtual) { + void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset) { for (Path_t::reverse_iterator i = Path->rbegin(), e = Path->rend(); i != e; ++i) { const CXXRecordDecl *RD = i->first; - int64_t Offset = i->second; + int64_t OverrideOffset = i->second; for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; ++mi) { if (!mi->isVirtual()) @@ -272,7 +311,7 @@ public: m = wrap(CGM.GetAddrOfFunction(MD, Ty)); } - OverrideMethod(MD, m, MorallyVirtual, Offset); + OverrideMethod(MD, m, MorallyVirtual, OverrideOffset, Offset); } } } @@ -291,7 +330,7 @@ public: } // If we can find a previously allocated slot for this, reuse it. - if (OverrideMethod(MD, m, MorallyVirtual, Offset)) + if (OverrideMethod(MD, m, MorallyVirtual, Offset, Offset)) return; // else allocate a new slot. @@ -344,7 +383,7 @@ public: llvm::Constant *e = 0; D(VCalls.insert(VCalls.begin(), 673)); D(VCalls.push_back(672)); - methods.insert(methods.begin() + InsertionPoint, VCalls.size()/*+2*/, e); + methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e); // The vcalls come first... for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(), e = VCalls.rend(); @@ -380,7 +419,9 @@ public: int VCallInsertionPoint = methods.size(); if (!DeferVCalls) { insertVCalls(VCallInsertionPoint); - } + } else + // FIXME: just for extra, or for all uses of VCalls.size post this? + extra = -VCalls.size(); if (ForVirtualBase) { D(methods.push_back(wrap(668))); @@ -463,7 +504,7 @@ public: AddMethods(RD, MorallyVirtual, Offset); if (Path) - OverrideMethods(Path, MorallyVirtual); + OverrideMethods(Path, MorallyVirtual, Offset); return end(RD, offsets, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, Offset, ForVirtualBase, Path); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 5206f447f8d0..ba93e5d0ebc8 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -167,18 +167,20 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, Builder.SetInsertPoint(EntryBB); + QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0); + // Emit subprogram debug descriptor. // FIXME: The cast here is a huge hack. if (CGDebugInfo *DI = getDebugInfo()) { DI->setLocation(StartLoc); if (isa<FunctionDecl>(D)) { - DI->EmitFunctionStart(CGM.getMangledName(GD), RetTy, CurFn, Builder); + DI->EmitFunctionStart(CGM.getMangledName(GD), FnType, CurFn, Builder); } else { // Just use LLVM function name. // FIXME: Remove unnecessary conversion to std::string when API settles. DI->EmitFunctionStart(std::string(Fn->getName()).c_str(), - RetTy, CurFn, Builder); + FnType, CurFn, Builder); } } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 722d002c19f5..639e683f0369 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -34,6 +34,7 @@ namespace llvm { class LLVMContext; class Module; class SwitchInst; + class Twine; class Value; } @@ -355,6 +356,7 @@ public: void BlockForwardSelf(); llvm::Value *LoadBlockStruct(); + uint64_t AllocateBlockDecl(const BlockDeclRefExpr *E); llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E); const llvm::Type *BuildByRefType(const ValueDecl *D); @@ -508,7 +510,7 @@ public: /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, - const char *Name = "tmp"); + 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. @@ -816,7 +818,9 @@ public: LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); - + LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E); + LValue EmitPointerToDataMemberLValue(const QualifiedDeclRefExpr *E); + llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); LValue EmitLValueForField(llvm::Value* Base, FieldDecl* Field, @@ -841,7 +845,8 @@ public: LValue EmitObjCKVCRefLValue(const ObjCImplicitSetterGetterRefExpr *E); LValue EmitObjCSuperExprLValue(const ObjCSuperExpr *E); LValue EmitStmtExprLValue(const StmtExpr *E); - + LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E); + //===--------------------------------------------------------------------===// // Scalar Expression Emission //===--------------------------------------------------------------------===// diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 4763b7fc1ee2..ea84829b78a5 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -825,7 +825,7 @@ llvm::Constant * CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, const char *Name) { // Convert Name to be a uniqued string from the IdentifierInfo table. - Name = getContext().Idents.get(Name).getName(); + Name = getContext().Idents.get(Name).getNameStart(); return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl()); } @@ -911,7 +911,7 @@ llvm::Constant * CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty, const char *Name) { // Convert Name to be a uniqued string from the IdentifierInfo table. - Name = getContext().Idents.get(Name).getName(); + Name = getContext().Idents.get(Name).getNameStart(); return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0); } @@ -1254,7 +1254,7 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { // Unique the name through the identifier table. const char *AliaseeName = AA->getAliasee().c_str(); - AliaseeName = getContext().Idents.get(AliaseeName).getName(); + AliaseeName = getContext().Idents.get(AliaseeName).getNameStart(); // Create a reference to the named value. This ensures that it is emitted // if a deferred decl. @@ -1341,7 +1341,7 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, cast<llvm::FunctionType>(getTypes().ConvertType(Type)); // Unique the name through the identifier table. - Name = getContext().Idents.get(Name).getName(); + Name = getContext().Idents.get(Name).getNameStart(); return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD)); } diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index fd772748dbda..2e6034bbcd97 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -248,7 +248,12 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { FD = PrimaryTemplate->getTemplatedDecl(); } - mangleBareFunctionType(FD->getType()->getAs<FunctionType>(), MangleReturnType); + // Do the canonicalization out here because parameter types can + // undergo additional canonicalization (e.g. array decay). + FunctionType *FT = cast<FunctionType>(Context.getASTContext() + .getCanonicalType(FD->getType())); + + mangleBareFunctionType(FT, MangleReturnType); } static bool isStdNamespace(const DeclContext *DC) { @@ -705,7 +710,7 @@ void CXXNameMangler::mangleType(QualType T) { // Only operate on the canonical type! T = Context.getASTContext().getCanonicalType(T); - bool IsSubstitutable = !isa<BuiltinType>(T); + bool IsSubstitutable = T.hasQualifiers() || !isa<BuiltinType>(T); if (IsSubstitutable && mangleSubstitution(T)) return; @@ -1236,10 +1241,7 @@ static bool isCharSpecialization(QualType T, const char *Name) { if (!isCharType(TemplateArgs[0].getAsType())) return false; - if (strcmp(SD->getIdentifier()->getName(), Name) != 0) - return false; - - return true; + return SD->getIdentifier()->getName() == Name; } bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index 59f579f7b17e..852bba4ef033 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -353,11 +353,17 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, return ABIArgInfo::getDirect(); } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - // Structures with flexible arrays are always indirect. - if (const RecordType *RT = RetTy->getAsStructureType()) + if (const RecordType *RT = RetTy->getAsStructureType()) { + // 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); + + // Structures with flexible arrays are always indirect. if (RT->getDecl()->hasFlexibleArrayMember()) return ABIArgInfo::getIndirect(0); - + } + // If specified, structs and unions are always indirect. if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType()) return ABIArgInfo::getIndirect(0); @@ -1744,14 +1750,14 @@ const ABIInfo &CodeGenTypes::getABIInfo() const { return *(TheABIInfo = new SystemZABIInfo()); case llvm::Triple::x86: - if (Triple.getOS() == llvm::Triple::Darwin) - return *(TheABIInfo = new X86_32ABIInfo(Context, true, true)); - switch (Triple.getOS()) { + case llvm::Triple::Darwin: + return *(TheABIInfo = new X86_32ABIInfo(Context, true, true)); case llvm::Triple::Cygwin: - case llvm::Triple::DragonFly: case llvm::Triple::MinGW32: case llvm::Triple::MinGW64: + case llvm::Triple::AuroraUX: + case llvm::Triple::DragonFly: case llvm::Triple::FreeBSD: case llvm::Triple::OpenBSD: return *(TheABIInfo = new X86_32ABIInfo(Context, false, true)); diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index a5a48adcf028..ae8119d33d64 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -38,7 +38,8 @@ Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple, DarwinVersion[2] = _DarwinVersion[2]; llvm::raw_string_ostream(MacosxVersionMin) - << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1]; + << "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.' + << DarwinVersion[1]; // FIXME: Lift default up. IPhoneOSVersionMin = "3.0"; @@ -54,7 +55,6 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, GCCVersion[2] = _GCCVersion[2]; // Set up the tool chain paths to match gcc. - ToolChainDir = "i686-apple-darwin"; ToolChainDir += llvm::utostr(DarwinVersion[0]); ToolChainDir += "/"; @@ -64,6 +64,26 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, ToolChainDir += '.'; ToolChainDir += llvm::utostr(GCCVersion[2]); + // Try the next major version if that tool chain dir is invalid. + std::string Tmp = "/usr/lib/gcc/" + ToolChainDir; + if (!llvm::sys::Path(Tmp).exists()) { + std::string Next = "i686-apple-darwin"; + Next += llvm::utostr(DarwinVersion[0] + 1); + Next += "/"; + Next += llvm::utostr(GCCVersion[0]); + Next += '.'; + Next += llvm::utostr(GCCVersion[1]); + Next += '.'; + Next += llvm::utostr(GCCVersion[2]); + + // Use that if it exists, otherwise hope the user isn't linking. + // + // FIXME: Drop dependency on gcc's tool chain. + Tmp = "/usr/lib/gcc/" + Next; + if (llvm::sys::Path(Tmp).exists()) + ToolChainDir = Next; + } + std::string Path; if (getArchName() == "x86_64") { Path = getHost().getDriver().Dir; @@ -676,6 +696,7 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/sfw/lib"); getFilePaths().push_back("/opt/gcc4/lib"); + getFilePaths().push_back("/opt/gcc4/lib/gcc/i386-pc-solaris2.11/4.2.4"); } diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index fc91e4c43799..c9d0b266d1cc 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -142,10 +142,15 @@ void Clang::AddPreprocessingOptions(const Driver &D, continue; if (A->getOption().matches(options::OPT_include)) { + // Use PCH if the user requested it, except for C++ (for now). + bool UsePCH = D.CCCUsePCH; + if (types::isCXX(Inputs[0].getType())) + UsePCH = false; + bool FoundPTH = false; bool FoundPCH = false; llvm::sys::Path P(A->getValue(Args)); - if (D.CCCUsePCH) { + if (UsePCH) { P.appendSuffix("pch"); if (P.exists()) FoundPCH = true; @@ -164,8 +169,8 @@ void Clang::AddPreprocessingOptions(const Driver &D, if (!FoundPCH && !FoundPTH) { P.appendSuffix("gch"); if (P.exists()) { - FoundPCH = D.CCCUsePCH; - FoundPTH = !D.CCCUsePCH; + FoundPCH = UsePCH; + FoundPTH = !UsePCH; } else P.eraseSuffix(); @@ -173,7 +178,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, if (FoundPCH || FoundPTH) { A->claim(); - if (D.CCCUsePCH) + if (UsePCH) CmdArgs.push_back("-include-pch"); else CmdArgs.push_back("-include-pth"); @@ -528,7 +533,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-E"); } else if (isa<PrecompileJobAction>(JA)) { - if (D.CCCUsePCH) + // Use PCH if the user requested it, except for C++ (for now). + bool UsePCH = D.CCCUsePCH; + if (types::isCXX(Inputs[0].getType())) + UsePCH = false; + + if (UsePCH) CmdArgs.push_back("-emit-pch"); else CmdArgs.push_back("-emit-pth"); @@ -759,7 +769,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // option. if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { if (Std->getOption().matches(options::OPT_ansi)) - CmdArgs.push_back("-std=c89"); + if (types::isCXX(InputType)) + CmdArgs.push_back("-std=c++98"); + else + CmdArgs.push_back("-std=c89"); else Std->render(Args, CmdArgs); @@ -2149,7 +2162,7 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); + Args.MakeArgString(getToolChain().GetProgramPath(C, "gas")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -2164,18 +2177,19 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, if ((!Args.hasArg(options::OPT_nostdlib)) && (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); - CmdArgs.push_back("__start"); + CmdArgs.push_back("_start"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); + CmdArgs.push_back("-dn"); } else { - CmdArgs.push_back("--eh-frame-hdr"); +// CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } else { - CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back("--dynamic-linker"); CmdArgs.push_back("/lib/ld.so.1"); // 64Bit Path /lib/amd64/ld.so.1 } } @@ -2193,11 +2207,14 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o"))); } else { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); +// CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); } + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o"))); } CmdArgs.push_back(MakeFormattedString(Args, @@ -2242,8 +2259,8 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o"))); - else - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); +// else +// CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); } const char *Exec = diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index d3475b5236d9..c0415bf550f8 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -21,11 +21,20 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" #include "llvm/Support/Compiler.h" +#include "llvm/System/Path.h" using namespace clang; -ASTUnit::ASTUnit(Diagnostic &_Diags) : Diags(_Diags) { } -ASTUnit::~ASTUnit() { } +ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) { + Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer()); +} +ASTUnit::~ASTUnit() { + if (tempFile) + llvm::sys::Path(getPCHFileName()).eraseFromDisk(); + + // The ASTUnit object owns the DiagnosticClient. + delete Diags.getClient(); +} namespace { @@ -80,17 +89,18 @@ const std::string &ASTUnit::getOriginalSourceFileName() { return dyn_cast<PCHReader>(Ctx->getExternalSource())->getOriginalSourceFile(); } -FileManager &ASTUnit::getFileManager() { - return HeaderInfo->getFileMgr(); +const std::string &ASTUnit::getPCHFileName() { + return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName(); } ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, - Diagnostic &Diags, - FileManager &FileMgr, - std::string *ErrMsg) { - llvm::OwningPtr<ASTUnit> AST(new ASTUnit(Diags)); - - AST->HeaderInfo.reset(new HeaderSearch(FileMgr)); + std::string *ErrMsg, + DiagnosticClient *diagClient, + bool OnlyLocalDecls, + bool UseBumpAllocator) { + llvm::OwningPtr<ASTUnit> AST(new ASTUnit(diagClient)); + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); // Gather Info for preprocessor construction later on. @@ -103,7 +113,8 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, llvm::OwningPtr<PCHReader> Reader; llvm::OwningPtr<ExternalASTSource> Source; - Reader.reset(new PCHReader(AST->getSourceManager(), FileMgr, AST->Diags)); + Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(), + AST->Diags)); Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, Predefines, Counter)); @@ -138,7 +149,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, PP.getIdentifierTable(), PP.getSelectorTable(), PP.getBuiltinInfo(), - /* FreeMemory = */ true, + /* FreeMemory = */ !UseBumpAllocator, /* size_reserve = */0)); ASTContext &Context = *AST->Ctx.get(); diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 276599470b78..55f274005909 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -196,7 +196,7 @@ void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { case Decl::Function: { FunctionDecl* FD = cast<FunctionDecl>(D); - if (Opts.AnalyzeSpecificFunction.size() > 0 && + if (!Opts.AnalyzeSpecificFunction.empty() && Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName()) break; @@ -273,6 +273,9 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { !Ctx->getSourceManager().isFromMainFile(D->getLocation())) return; + // Clear the AnalysisManager of old AnalysisContexts. + Mgr->ClearContexts(); + // Dispatch on the actions. for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) (*I)(*Mgr, D); diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index e7fc5660ad20..339a1c466bc9 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -20,11 +20,12 @@ #include "clang/Basic/OnDiskHashTable.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" -#include "llvm/ADT/StringMap.h" // FIXME: put this somewhere else? #ifndef S_ISDIR @@ -69,7 +70,7 @@ public: bool isFile() const { return Kind == IsFE; } - const char* getCString() const { + llvm::StringRef getString() const { return Kind == IsFE ? FE->getName() : Path; } @@ -113,14 +114,14 @@ public: typedef const PTHEntry& data_type_ref; static unsigned ComputeHash(PTHEntryKeyVariant V) { - return BernsteinHash(V.getCString()); + return llvm::HashString(V.getString()); } static std::pair<unsigned,unsigned> EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V, const PTHEntry& E) { - unsigned n = strlen(V.getCString()) + 1 + 1; + unsigned n = V.getString().size() + 1 + 1; ::Emit16(Out, n); unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0); @@ -133,7 +134,7 @@ public: // Emit the entry kind. ::Emit8(Out, (unsigned) V.getKind()); // Emit the string. - Out.write(V.getCString(), n - 1); + Out.write(V.getString().data(), n - 1); } static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V, @@ -516,7 +517,7 @@ public: ~StatListener() {} int stat(const char *path, struct stat *buf) { - int result = ::stat(path, buf); + int result = StatSysCallCache::stat(path, buf); if (result != 0) // Failed 'stat'. PM.insert(path, PTHEntry()); @@ -553,7 +554,8 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { PTHWriter PW(*OS, PP); // Install the 'stat' system call listener in the FileManager. - PP.getFileManager().setStatCache(new StatListener(PW.getPM())); + StatListener *StatCache = new StatListener(PW.getPM()); + PP.getFileManager().addStatCache(StatCache, /*AtBeginning=*/true); // Lex through the entire file. This will populate SourceManager with // all of the header information. @@ -562,7 +564,7 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); // Generate the PTH file. - PP.getFileManager().setStatCache(0); + PP.getFileManager().removeStatCache(StatCache); PW.GeneratePTH(&MainFileName); } @@ -584,12 +586,12 @@ public: typedef data_type data_type_ref; static unsigned ComputeHash(PTHIdKey* key) { - return BernsteinHash(key->II->getName()); + return llvm::HashString(key->II->getName()); } static std::pair<unsigned,unsigned> EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) { - unsigned n = strlen(key->II->getName()) + 1; + unsigned n = key->II->getLength() + 1; ::Emit16(Out, n); return std::make_pair(n, sizeof(uint32_t)); } @@ -598,7 +600,7 @@ public: // Record the location of the key data. This is used when generating // the mapping from persistent IDs to strings. key->FileOffset = Out.tell(); - Out.write(key->II->getName(), n); + Out.write(key->II->getNameStart(), n); } static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID, diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp index bc45cc422585..0e4f83ff09f5 100644 --- a/lib/Frontend/GeneratePCH.cpp +++ b/lib/Frontend/GeneratePCH.cpp @@ -53,7 +53,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP, // Install a stat() listener to keep track of all of the stat() // calls. StatCalls = new MemorizeStatCalls; - PP.getFileManager().setStatCache(StatCalls); + PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/true); } void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 822a5baf5972..25316bed9fb4 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -369,6 +369,12 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnu", triple); + // Gentoo x86 2009.1 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); // Gentoo x86 2009.0 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", @@ -386,6 +392,11 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, "i486-pc-linux-gnu", "i486-pc-linux-gnu", triple); + // Ubuntu 9.04 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i486-linux-gnu", + "i486-linux-gnu", + triple); // Gentoo amd64 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", @@ -400,6 +411,8 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, AddPath("/usr/include/c++/4.2", System, true, false, false); break; case llvm::Triple::Solaris: + // Solaris - Fall though.. + case llvm::Triple::AuroraUX: // AuroraUX AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", "i386-pc-solaris2.11", diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 0f3b4b8236be..b1a0a5ee8d51 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -317,13 +317,22 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineBuiltinMacro(Buf, "_GNU_SOURCE=1"); } - // Filter out some microsoft extensions when trying to parse in ms-compat - // mode. if (LangOpts.Microsoft) { + // Filter out some microsoft extensions when trying to parse in ms-compat + // mode. DefineBuiltinMacro(Buf, "__int8=__INT8_TYPE__"); DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__"); DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__"); DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__"); + // Work around some issues with Visual C++ headerws. + if (LangOpts.CPlusPlus) { + // Since we define wchar_t in C++ mode. + DefineBuiltinMacro(Buf, "_WCHAR_T_DEFINED=1"); + DefineBuiltinMacro(Buf, "_NATIVE_WCHAR_T_DEFINED=1"); + // FIXME: This should be temporary until we have a __pragma + // solution, to avoid some errors flagged in VC++ headers. + DefineBuiltinMacro(Buf, "_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=0"); + } } if (LangOpts.Optimize) @@ -365,8 +374,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Buf); DefineType("__SIZE_TYPE__", TI.getSizeType(), Buf); DefineType("__WCHAR_TYPE__", TI.getWCharType(), Buf); - // FIXME: TargetInfo hookize __WINT_TYPE__. - DefineBuiltinMacro(Buf, "__WINT_TYPE__=int"); + DefineType("__WINT_TYPE__", TI.getWIntType(), Buf); DefineFloatMacros(Buf, "FLT", &TI.getFloatFormat()); DefineFloatMacros(Buf, "DBL", &TI.getDoubleFormat()); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index e61668dd3177..9c6059b1c7c0 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -18,6 +18,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" @@ -27,6 +28,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" @@ -335,8 +337,6 @@ void PCHValidator::ReadCounter(unsigned Value) { PP.setCounterValue(Value); } - - //===----------------------------------------------------------------------===// // PCH reader implementation //===----------------------------------------------------------------------===// @@ -345,7 +345,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, const char *isysroot) : Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), - SemaObj(0), PP(&PP), Context(Context), Consumer(0), + SemaObj(0), PP(&PP), Context(Context), StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), @@ -362,7 +362,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, Diagnostic &Diags, const char *isysroot) : SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags), - SemaObj(0), PP(0), Context(0), Consumer(0), + SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), @@ -383,7 +383,7 @@ Expr *PCHReader::ReadDeclExpr() { } Expr *PCHReader::ReadTypeExpr() { - return dyn_cast_or_null<Expr>(ReadStmt(Stream)); + return dyn_cast_or_null<Expr>(ReadStmt(DeclsCursor)); } @@ -411,7 +411,7 @@ public: unsigned R = 5381; for (unsigned I = 0; I != N; ++I) if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) - R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R); + R = llvm::HashString(II->getName(), R); return R; } @@ -521,7 +521,7 @@ public: } static unsigned ComputeHash(const internal_key_type& a) { - return BernsteinHash(a.first, a.second); + return llvm::HashString(llvm::StringRef(a.first, a.second)); } // This hopefully will just get inlined and removed by the optimizer. @@ -731,7 +731,7 @@ class VISIBILITY_HIDDEN PCHStatLookupTrait { typedef PCHStatData data_type; static unsigned ComputeHash(const char *path) { - return BernsteinHash(path); + return llvm::HashString(path); } static internal_key_type GetInternalKey(const char *path) { return path; } @@ -794,7 +794,7 @@ public: // If we don't get a hit in the PCH file just forward to 'stat'. if (I == Cache->end()) { ++NumStatMisses; - return ::stat(path, buf); + return StatSysCallCache::stat(path, buf); } ++NumStatHits; @@ -1158,15 +1158,7 @@ PCHReader::ReadPCHBlock() { if (Code == llvm::bitc::ENTER_SUBBLOCK) { switch (Stream.ReadSubBlockID()) { - case pch::TYPES_BLOCK_ID: // Skip types block (lazily loaded) - default: // Skip unknown content. - if (Stream.SkipBlock()) { - Error("malformed block record in PCH file"); - return Failure; - } - break; - - case pch::DECLS_BLOCK_ID: + case pch::DECLTYPES_BLOCK_ID: // We lazily load the decls block, but we want to set up the // DeclsCursor cursor to point into it. Clone our current bitcode // cursor to it, enter the block and read the abbrevs in that block. @@ -1174,7 +1166,7 @@ PCHReader::ReadPCHBlock() { DeclsCursor = Stream; if (Stream.SkipBlock() || // Skip with the main cursor. // Read the abbrevs. - ReadBlockAbbrevs(DeclsCursor, pch::DECLS_BLOCK_ID)) { + ReadBlockAbbrevs(DeclsCursor, pch::DECLTYPES_BLOCK_ID)) { Error("malformed block record in PCH file"); return Failure; } @@ -1352,13 +1344,16 @@ PCHReader::ReadPCHBlock() { } break; - case pch::STAT_CACHE: - FileMgr.setStatCache( - new PCHStatCache((const unsigned char *)BlobStart + Record[0], - (const unsigned char *)BlobStart, - NumStatHits, NumStatMisses)); + case pch::STAT_CACHE: { + PCHStatCache *MyStatCache = + new PCHStatCache((const unsigned char *)BlobStart + Record[0], + (const unsigned char *)BlobStart, + NumStatHits, NumStatMisses); + FileMgr.addStatCache(MyStatCache); + StatCache = MyStatCache; break; - + } + case pch::EXT_VECTOR_DECLS: if (!ExtVectorDecls.empty()) { Error("duplicate EXT_VECTOR_DECLS record in PCH file"); @@ -1466,7 +1461,8 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { SourceMgr.ClearPreallocatedSLocEntries(); // Remove the stat cache. - FileMgr.setStatCache(0); + if (StatCache) + FileMgr.removeStatCache((PCHStatCache*)StatCache); return IgnorePCH; } @@ -1509,7 +1505,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { IdentifierInfo *II = Identifiers[I]; // Look in the on-disk hash table for an entry for PCHIdentifierLookupTrait Info(*this, II); - std::pair<const char*, unsigned> Key(II->getName(), II->getLength()); + std::pair<const char*, unsigned> Key(II->getNameStart(), II->getLength()); PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info); if (Pos == IdTable->end()) continue; @@ -1593,6 +1589,11 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { if (unsigned ObjCClassRedef = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef); + if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR]) + Context->setBlockDescriptorType(GetType(String)); + if (unsigned String + = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR]) + Context->setBlockDescriptorExtendedType(GetType(String)); } /// \brief Retrieve the name of the original source file name @@ -1770,15 +1771,15 @@ void PCHReader::ReadComments(std::vector<SourceRange> &Comments) { QualType PCHReader::ReadTypeRecord(uint64_t Offset) { // Keep track of where we are in the stream, then jump back there // after reading this type. - SavedStreamPosition SavedPosition(Stream); + SavedStreamPosition SavedPosition(DeclsCursor); // Note that we are loading a type record. LoadingTypeOrDecl Loading(*this); - Stream.JumpToBit(Offset); + DeclsCursor.JumpToBit(Offset); RecordData Record; - unsigned Code = Stream.ReadCode(); - switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) { + unsigned Code = DeclsCursor.ReadCode(); + switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) { case pch::TYPE_EXT_QUAL: { assert(Record.size() == 2 && "Incorrect encoding of extended qualifier type"); @@ -1839,30 +1840,6 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { ASM, IndexTypeQuals); } - case pch::TYPE_CONSTANT_ARRAY_WITH_EXPR: { - QualType ElementType = GetType(Record[0]); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - SourceLocation LBLoc = SourceLocation::getFromRawEncoding(Record[3]); - SourceLocation RBLoc = SourceLocation::getFromRawEncoding(Record[4]); - unsigned Idx = 5; - llvm::APInt Size = ReadAPInt(Record, Idx); - return Context->getConstantArrayWithExprType(ElementType, - Size, ReadTypeExpr(), - ASM, IndexTypeQuals, - SourceRange(LBLoc, RBLoc)); - } - - case pch::TYPE_CONSTANT_ARRAY_WITHOUT_EXPR: { - QualType ElementType = GetType(Record[0]); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - unsigned Idx = 3; - llvm::APInt Size = ReadAPInt(Record, Idx); - return Context->getConstantArrayWithoutExprType(ElementType, Size, - ASM, IndexTypeQuals); - } - case pch::TYPE_INCOMPLETE_ARRAY: { QualType ElementType = GetType(Record[0]); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; @@ -1987,20 +1964,184 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getObjCObjectPointerType(OIT, Protos.data(), NumProtos); } - case pch::TYPE_OBJC_PROTOCOL_LIST: { + case pch::TYPE_SUBST_TEMPLATE_TYPE_PARM: { unsigned Idx = 0; - QualType OIT = GetType(Record[Idx++]); - unsigned NumProtos = Record[Idx++]; - llvm::SmallVector<ObjCProtocolDecl*, 4> Protos; - for (unsigned I = 0; I != NumProtos; ++I) - Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++]))); - return Context->getObjCProtocolListType(OIT, Protos.data(), NumProtos); + QualType Parm = GetType(Record[Idx++]); + QualType Replacement = GetType(Record[Idx++]); + return + Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm), + Replacement); } } // Suppress a GCC warning return QualType(); } +namespace { + +class TypeLocReader : public TypeLocVisitor<TypeLocReader> { + PCHReader &Reader; + const PCHReader::RecordData &Record; + unsigned &Idx; + +public: + TypeLocReader(PCHReader &Reader, const PCHReader::RecordData &Record, + unsigned &Idx) + : Reader(Reader), Record(Record), Idx(Idx) { } + + // We want compile-time assurance that we've enumerated all of + // these, so unfortunately we have to declare them first, then + // define them out-of-line. +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + void VisitFunctionTypeLoc(FunctionTypeLoc); + void VisitArrayTypeLoc(ArrayTypeLoc); +}; + +} + +void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} +void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { + TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + TL.setCaretLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + TL.setAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + TL.setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { + TL.setLBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + if (Record[Idx++]) + TL.setSizeExpr(Reader.ReadDeclExpr()); + else + TL.setSizeExpr(0); +} +void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitDependentSizedArrayTypeLoc( + DependentSizedArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { + TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); + } +} +void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTypenameTypeLoc(TypenameTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setHasBaseTypeAsWritten(Record[Idx++]); + TL.setHasProtocolsAsWritten(Record[Idx++]); + if (TL.hasProtocolsAsWritten()) + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); +} + +DeclaratorInfo *PCHReader::GetDeclaratorInfo(const RecordData &Record, + unsigned &Idx) { + QualType InfoTy = GetType(Record[Idx++]); + if (InfoTy.isNull()) + return 0; + + DeclaratorInfo *DInfo = getContext()->CreateDeclaratorInfo(InfoTy); + TypeLocReader TLR(*this, Record, Idx); + for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + TLR.Visit(TL); + return DInfo; +} QualType PCHReader::GetType(pch::TypeID ID) { unsigned FastQuals = ID & Qualifiers::FastMask; @@ -2374,7 +2515,10 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) { // All of the strings in the PCH file are preceded by a 16-bit // length. Extract that 16-bit length to avoid having to execute // strlen(). - const char *StrLenPtr = Str - 2; + // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as + // unsigned integers. This is important to avoid integer overflow when + // we cast them to 'unsigned'. + const unsigned char *StrLenPtr = (const unsigned char*) Str - 2; unsigned StrLen = (((unsigned) StrLenPtr[0]) | (((unsigned) StrLenPtr[1]) << 8)) - 1; IdentifiersLoaded[ID - 1] diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index b6732561dff0..d1cb461640b7 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -18,7 +18,6 @@ #include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/Expr.h" -#include "clang/AST/TypeLocVisitor.h" using namespace clang; @@ -86,6 +85,7 @@ void PCHDeclReader::VisitDecl(Decl *D) { D->setImplicit(Record[Idx++]); D->setUsed(Record[Idx++]); D->setAccess((AccessSpecifier)Record[Idx++]); + D->setPCHLevel(Record[Idx++] + 1); } void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { @@ -149,84 +149,11 @@ void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { ECD->setInitVal(Reader.ReadAPSInt(Record, Idx)); } -namespace { - -class TypeLocReader : public TypeLocVisitor<TypeLocReader> { - PCHReader &Reader; - const PCHReader::RecordData &Record; - unsigned &Idx; - -public: - TypeLocReader(PCHReader &Reader, const PCHReader::RecordData &Record, - unsigned &Idx) - : Reader(Reader), Record(Record), Idx(Idx) { } - -#define ABSTRACT_TYPELOC(CLASS) -#define TYPELOC(CLASS, PARENT) \ - void Visit##CLASS(CLASS TyLoc); -#include "clang/AST/TypeLocNodes.def" - - void VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A type loc wrapper was not handled!"); - } -}; - -} - -void TypeLocReader::VisitQualifiedLoc(QualifiedLoc TyLoc) { - // nothing to do -} -void TypeLocReader::VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { - TyLoc.setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitTypedefLoc(TypedefLoc TyLoc) { - TyLoc.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) { - TyLoc.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) { - TyLoc.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TyLoc.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - for (unsigned i = 0, e = TyLoc.getNumProtocols(); i != e; ++i) - TyLoc.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitPointerLoc(PointerLoc TyLoc) { - TyLoc.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitBlockPointerLoc(BlockPointerLoc TyLoc) { - TyLoc.setCaretLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitMemberPointerLoc(MemberPointerLoc TyLoc) { - TyLoc.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitReferenceLoc(ReferenceLoc TyLoc) { - TyLoc.setAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitFunctionLoc(FunctionLoc TyLoc) { - TyLoc.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TyLoc.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - for (unsigned i = 0, e = TyLoc.getNumArgs(); i != e; ++i) - TyLoc.setArg(i, cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); -} -void TypeLocReader::VisitArrayLoc(ArrayLoc TyLoc) { - TyLoc.setLBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TyLoc.setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - if (Record[Idx++]) - TyLoc.setSizeExpr(Reader.ReadDeclExpr()); -} - void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { VisitValueDecl(DD); - QualType InfoTy = Reader.GetType(Record[Idx++]); - if (InfoTy.isNull()) - return; - - DeclaratorInfo *DInfo = Reader.getContext()->CreateDeclaratorInfo(InfoTy); - TypeLocReader TLR(Reader, Record, Idx); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) - TLR.Visit(TL); - DD->setDeclaratorInfo(DInfo); + DeclaratorInfo *DInfo = Reader.GetDeclaratorInfo(Record, Idx); + if (DInfo) + DD->setDeclaratorInfo(DInfo); } void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 64a678ea450b..fb48df332121 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclContextInternals.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" @@ -30,6 +31,7 @@ #include "clang/Basic/Version.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" @@ -117,23 +119,6 @@ void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) { Code = pch::TYPE_CONSTANT_ARRAY; } -void PCHTypeWriter -::VisitConstantArrayWithExprType(const ConstantArrayWithExprType *T) { - VisitArrayType(T); - Writer.AddSourceLocation(T->getLBracketLoc(), Record); - Writer.AddSourceLocation(T->getRBracketLoc(), Record); - Writer.AddAPInt(T->getSize(), Record); - Writer.AddStmt(T->getSizeExpr()); - Code = pch::TYPE_CONSTANT_ARRAY_WITH_EXPR; -} - -void PCHTypeWriter -::VisitConstantArrayWithoutExprType(const ConstantArrayWithoutExprType *T) { - VisitArrayType(T); - Writer.AddAPInt(T->getSize(), Record); - Code = pch::TYPE_CONSTANT_ARRAY_WITHOUT_EXPR; -} - void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) { VisitArrayType(T); Code = pch::TYPE_INCOMPLETE_ARRAY; @@ -225,6 +210,14 @@ void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) { } void +PCHTypeWriter::VisitSubstTemplateTypeParmType( + const SubstTemplateTypeParmType *T) { + Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record); + Writer.AddTypeRef(T->getReplacementType(), Record); + Code = pch::TYPE_SUBST_TEMPLATE_TYPE_PARM; +} + +void PCHTypeWriter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { // FIXME: Serialize this type (C++ only) @@ -255,13 +248,150 @@ PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { Code = pch::TYPE_OBJC_OBJECT_POINTER; } -void PCHTypeWriter::VisitObjCProtocolListType(const ObjCProtocolListType *T) { - Writer.AddTypeRef(T->getBaseType(), Record); - Record.push_back(T->getNumProtocols()); - for (ObjCProtocolListType::qual_iterator I = T->qual_begin(), - E = T->qual_end(); I != E; ++I) - Writer.AddDeclRef(*I, Record); - Code = pch::TYPE_OBJC_PROTOCOL_LIST; +namespace { + +class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { + PCHWriter &Writer; + PCHWriter::RecordData &Record; + +public: + TypeLocWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) + : Writer(Writer), Record(Record) { } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + void VisitArrayTypeLoc(ArrayTypeLoc TyLoc); + void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc); +}; + +} + +void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} +void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} +void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getCaretLoc(), Record); +} +void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + Writer.AddSourceLocation(TL.getAmpLoc(), Record); +} +void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record); +} +void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} +void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) { + Writer.AddSourceLocation(TL.getLBracketLoc(), Record); + Writer.AddSourceLocation(TL.getRBracketLoc(), Record); + Record.push_back(TL.getSizeExpr() ? 1 : 0); + if (TL.getSizeExpr()) + Writer.AddStmt(TL.getSizeExpr()); +} +void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitDependentSizedArrayTypeLoc( + DependentSizedArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + Writer.AddDeclRef(TL.getArg(i), Record); +} +void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypenameTypeLoc(TypenameTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); +} +void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + Record.push_back(TL.hasBaseTypeAsWritten()); + Record.push_back(TL.hasProtocolsAsWritten()); + if (TL.hasProtocolsAsWritten()) + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); } //===----------------------------------------------------------------------===// @@ -411,8 +541,8 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(PP_MACRO_FUNCTION_LIKE); RECORD(PP_TOKEN); - // Types block. - BLOCK(TYPES_BLOCK); + // Decls and Types block. + BLOCK(DECLTYPES_BLOCK); RECORD(TYPE_EXT_QUAL); RECORD(TYPE_FIXED_WIDTH_INT); RECORD(TYPE_COMPLEX); @@ -435,12 +565,6 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(TYPE_ENUM); RECORD(TYPE_OBJC_INTERFACE); RECORD(TYPE_OBJC_OBJECT_POINTER); - RECORD(TYPE_OBJC_PROTOCOL_LIST); - // Statements and Exprs can occur in the Types block. - AddStmtsExprs(Stream, Record); - - // Decls block. - BLOCK(DECLS_BLOCK); RECORD(DECL_ATTR); RECORD(DECL_TRANSLATION_UNIT); RECORD(DECL_TYPEDEF); @@ -470,7 +594,7 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(DECL_BLOCK); RECORD(DECL_CONTEXT_LEXICAL); RECORD(DECL_CONTEXT_VISIBLE); - // Statements and Exprs can occur in the Decls block. + // Statements and Exprs can occur in the Decls and Types block. AddStmtsExprs(Stream, Record); #undef RECORD #undef BLOCK @@ -662,7 +786,7 @@ public: typedef const data_type& data_type_ref; static unsigned ComputeHash(const char *path) { - return BernsteinHash(path); + return llvm::HashString(path); } std::pair<unsigned,unsigned> @@ -878,10 +1002,10 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, std::vector<uint32_t> SLocEntryOffsets; RecordData PreloadSLocs; SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1); - for (SourceManager::sloc_entry_iterator - SLoc = SourceMgr.sloc_entry_begin() + 1, - SLocEnd = SourceMgr.sloc_entry_end(); - SLoc != SLocEnd; ++SLoc) { + for (unsigned I = 1, N = SourceMgr.sloc_entry_size(); I != N; ++I) { + // Get this source location entry. + const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I); + // Record the offset of this source-location entry. SLocEntryOffsets.push_back(Stream.GetCurrentBitNo()); @@ -956,9 +1080,8 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Compute the token length for this macro expansion. unsigned NextOffset = SourceMgr.getNextOffset(); - SourceManager::sloc_entry_iterator NextSLoc = SLoc; - if (++NextSLoc != SLocEnd) - NextOffset = NextSLoc->getOffset(); + if (I + 1 != N) + NextOffset = SourceMgr.getSLocEntry(I + 1).getOffset(); Record.push_back(NextOffset - SLoc->getOffset() - 1); Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record); } @@ -1019,6 +1142,7 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { // Loop over all the macro definitions that are live at the end of the file, // emitting each to the PP section. + // FIXME: Make sure that this sees macros defined in included PCH files. for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); I != E; ++I) { // FIXME: This emits macros in hash table order, we should do it in a stable @@ -1152,22 +1276,6 @@ void PCHWriter::WriteType(QualType T) { FlushStmts(); } -/// \brief Write a block containing all of the types. -void PCHWriter::WriteTypesBlock(ASTContext &Context) { - // Enter the types block. - Stream.EnterSubblock(pch::TYPES_BLOCK_ID, 2); - - // Emit all of the types that need to be emitted (so far). - while (!TypesToEmit.empty()) { - QualType T = TypesToEmit.front(); - TypesToEmit.pop(); - WriteType(T); - } - - // Exit the types block - Stream.ExitBlock(); -} - //===----------------------------------------------------------------------===// // Declaration Serialization //===----------------------------------------------------------------------===// @@ -1266,7 +1374,7 @@ public: unsigned R = 5381; for (unsigned I = 0; I != N; ++I) if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) - R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R); + R = llvm::HashString(II->getName(), R); return R; } @@ -1475,13 +1583,13 @@ public: : Writer(Writer), PP(PP) { } static unsigned ComputeHash(const IdentifierInfo* II) { - return clang::BernsteinHash(II->getName()); + return llvm::HashString(II->getName()); } std::pair<unsigned,unsigned> EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II, pch::IdentID ID) { - unsigned KeyLen = strlen(II->getName()) + 1; + unsigned KeyLen = II->getLength() + 1; unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 if (isInterestingIdentifier(II)) { DataLen += 2; // 2 bytes for builtin ID, flags @@ -1506,7 +1614,7 @@ public: // Record the location of the key data. This is used when generating // the mapping from persistent IDs to strings. Writer.SetIdentifierOffset(II, Out.tell()); - Out.write(II->getName(), KeyLen); + Out.write(II->getNameStart(), KeyLen); } void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II, @@ -1810,7 +1918,7 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, // The translation unit is the first declaration we'll emit. DeclIDs[Context.getTranslationUnitDecl()] = 1; - DeclsToEmit.push(Context.getTranslationUnitDecl()); + DeclTypesToEmit.push(Context.getTranslationUnitDecl()); // Make sure that we emit IdentifierInfos (and any attached // declarations) for builtins. @@ -1858,7 +1966,6 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, if (StatCalls && !isysroot) WriteStatCache(*StatCalls, isysroot); WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); - WritePreprocessor(PP); WriteComments(Context); // Write the record of special types. Record.clear(); @@ -1875,17 +1982,25 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, AddTypeRef(Context.getsigjmp_bufType(), Record); AddTypeRef(Context.ObjCIdRedefinitionType, Record); AddTypeRef(Context.ObjCClassRedefinitionType, Record); + AddTypeRef(Context.getRawBlockdescriptorType(), Record); + AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record); Stream.EmitRecord(pch::SPECIAL_TYPES, Record); // Keep writing types and declarations until all types and // declarations have been written. - do { - if (!DeclsToEmit.empty()) - WriteDeclsBlock(Context); - if (!TypesToEmit.empty()) - WriteTypesBlock(Context); - } while (!(DeclsToEmit.empty() && TypesToEmit.empty())); - + Stream.EnterSubblock(pch::DECLTYPES_BLOCK_ID, 3); + WriteDeclsBlockAbbrevs(); + while (!DeclTypesToEmit.empty()) { + DeclOrType DOT = DeclTypesToEmit.front(); + DeclTypesToEmit.pop(); + if (DOT.isType()) + WriteType(DOT.getType()); + else + WriteDecl(Context, DOT.getDecl()); + } + Stream.ExitBlock(); + + WritePreprocessor(PP); WriteMethodPool(SemaRef); WriteIdentifierTable(PP); @@ -1991,6 +2106,18 @@ void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) { Record.push_back(SID); } +void PCHWriter::AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record) { + if (DInfo == 0) { + AddTypeRef(QualType(), Record); + return; + } + + AddTypeRef(DInfo->getType(), Record); + TypeLocWriter TLW(*this, Record); + for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + TLW.Visit(TL); +} + void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { if (T.isNull()) { Record.push_back(pch::PREDEF_TYPE_NULL_ID); @@ -2007,7 +2134,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { // Assign it a new ID. This is the only time we enqueue a // qualified type, and it has no CV qualifiers. ID = NextTypeID++; - TypesToEmit.push(T); + DeclTypesToEmit.push(T); } // Encode the type qualifiers in the type reference. @@ -2061,7 +2188,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { // We haven't seen this type before. Assign it a new ID and put it // into the queue of types to emit. ID = NextTypeID++; - TypesToEmit.push(T); + DeclTypesToEmit.push(T); } // Encode the type qualifiers in the type reference. @@ -2079,7 +2206,7 @@ void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) { // We haven't seen this declaration before. Give it a new ID and // enqueue it in the list of declarations to emit. ID = DeclIDs.size(); - DeclsToEmit.push(const_cast<Decl *>(D)); + DeclTypesToEmit.push(const_cast<Decl *>(D)); } Record.push_back(ID); diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index ef7c5ec4b1a6..fbd9929e49d7 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -14,7 +14,6 @@ #include "clang/Frontend/PCHWriter.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" -#include "clang/AST/TypeLocVisitor.h" #include "llvm/Bitcode/BitstreamWriter.h" #include <cstdio> @@ -88,6 +87,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) { Record.push_back(D->isImplicit()); Record.push_back(D->isUsed()); Record.push_back(D->getAccess()); + Record.push_back(D->getPCHLevel()); } void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { @@ -149,84 +149,10 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { Writer.AddAPSInt(D->getInitVal(), Record); Code = pch::DECL_ENUM_CONSTANT; } -namespace { - -class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { - PCHWriter &Writer; - PCHWriter::RecordData &Record; - -public: - TypeLocWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) - : Writer(Writer), Record(Record) { } - -#define ABSTRACT_TYPELOC(CLASS) -#define TYPELOC(CLASS, PARENT) \ - void Visit##CLASS(CLASS TyLoc); -#include "clang/AST/TypeLocNodes.def" - - void VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A type loc wrapper was not handled!"); - } -}; - -} - -void TypeLocWriter::VisitQualifiedLoc(QualifiedLoc TyLoc) { - // nothing to do here -} -void TypeLocWriter::VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getStartLoc(), Record); -} -void TypeLocWriter::VisitTypedefLoc(TypedefLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getNameLoc(), Record); -} -void TypeLocWriter::VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getNameLoc(), Record); -} -void TypeLocWriter::VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getLAngleLoc(), Record); - Writer.AddSourceLocation(TyLoc.getRAngleLoc(), Record); - for (unsigned i = 0, e = TyLoc.getNumProtocols(); i != e; ++i) - Writer.AddSourceLocation(TyLoc.getProtocolLoc(i), Record); -} -void TypeLocWriter::VisitPointerLoc(PointerLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getStarLoc(), Record); -} -void TypeLocWriter::VisitBlockPointerLoc(BlockPointerLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getCaretLoc(), Record); -} -void TypeLocWriter::VisitMemberPointerLoc(MemberPointerLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getStarLoc(), Record); -} -void TypeLocWriter::VisitReferenceLoc(ReferenceLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getAmpLoc(), Record); -} -void TypeLocWriter::VisitFunctionLoc(FunctionLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getLParenLoc(), Record); - Writer.AddSourceLocation(TyLoc.getRParenLoc(), Record); - for (unsigned i = 0, e = TyLoc.getNumArgs(); i != e; ++i) - Writer.AddDeclRef(TyLoc.getArg(i), Record); -} -void TypeLocWriter::VisitArrayLoc(ArrayLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getLBracketLoc(), Record); - Writer.AddSourceLocation(TyLoc.getRBracketLoc(), Record); - Record.push_back(TyLoc.getSizeExpr() ? 1 : 0); - if (TyLoc.getSizeExpr()) - Writer.AddStmt(TyLoc.getSizeExpr()); -} void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); - DeclaratorInfo *DInfo = D->getDeclaratorInfo(); - if (DInfo == 0) { - Writer.AddTypeRef(QualType(), Record); - return; - } - - Writer.AddTypeRef(DInfo->getTypeLoc().getSourceType(), Record); - TypeLocWriter TLW(Writer, Record); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) - TLW.Visit(TL); + Writer.AddDeclaratorInfo(D->getDeclaratorInfo(), Record); } void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { @@ -448,6 +374,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { !D->isImplicit() && !D->isUsed() && D->getAccess() == AS_none && + D->getPCHLevel() == 0 && D->getStorageClass() == 0 && !D->hasCXXDirectInitializer() && // Can params have this ever? D->getObjCDeclQualifier() == 0) @@ -523,6 +450,7 @@ void PCHWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier + Abv->Add(BitCodeAbbrevOp(0)); // PCH level // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -607,80 +535,64 @@ static bool isRequiredDecl(const Decl *D, ASTContext &Context) { } } -/// \brief Write a block containing all of the declarations. -void PCHWriter::WriteDeclsBlock(ASTContext &Context) { - // Enter the declarations block. - Stream.EnterSubblock(pch::DECLS_BLOCK_ID, 3); - - // Output the abbreviations that we will use in this block. - WriteDeclsBlockAbbrevs(); - - // Emit all of the declarations. +void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) { RecordData Record; PCHDeclWriter W(*this, Context, Record); - while (!DeclsToEmit.empty()) { - // Pull the next declaration off the queue - Decl *D = DeclsToEmit.front(); - DeclsToEmit.pop(); - - // If this declaration is also a DeclContext, write blocks for the - // declarations that lexically stored inside its context and those - // declarations that are visible from its context. These blocks - // are written before the declaration itself so that we can put - // their offsets into the record for the declaration. - uint64_t LexicalOffset = 0; - uint64_t VisibleOffset = 0; - DeclContext *DC = dyn_cast<DeclContext>(D); - if (DC) { - LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); - VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); - } - // Determine the ID for this declaration - pch::DeclID &ID = DeclIDs[D]; - if (ID == 0) - ID = DeclIDs.size(); + // If this declaration is also a DeclContext, write blocks for the + // declarations that lexically stored inside its context and those + // declarations that are visible from its context. These blocks + // are written before the declaration itself so that we can put + // their offsets into the record for the declaration. + uint64_t LexicalOffset = 0; + uint64_t VisibleOffset = 0; + DeclContext *DC = dyn_cast<DeclContext>(D); + if (DC) { + LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); + VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); + } - unsigned Index = ID - 1; + // Determine the ID for this declaration + pch::DeclID &ID = DeclIDs[D]; + if (ID == 0) + ID = DeclIDs.size(); - // Record the offset for this declaration - if (DeclOffsets.size() == Index) - DeclOffsets.push_back(Stream.GetCurrentBitNo()); - else if (DeclOffsets.size() < Index) { - DeclOffsets.resize(Index+1); - DeclOffsets[Index] = Stream.GetCurrentBitNo(); - } + unsigned Index = ID - 1; - // Build and emit a record for this declaration - Record.clear(); - W.Code = (pch::DeclCode)0; - W.AbbrevToUse = 0; - W.Visit(D); - if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); - - if (!W.Code) { - fprintf(stderr, "Cannot serialize declaration of kind %s\n", - D->getDeclKindName()); - assert(false && "Unhandled declaration kind while generating PCH"); - exit(-1); - } - Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); + // Record the offset for this declaration + if (DeclOffsets.size() == Index) + DeclOffsets.push_back(Stream.GetCurrentBitNo()); + else if (DeclOffsets.size() < Index) { + DeclOffsets.resize(Index+1); + DeclOffsets[Index] = Stream.GetCurrentBitNo(); + } - // If the declaration had any attributes, write them now. - if (D->hasAttrs()) - WriteAttributeRecord(D->getAttrs()); + // Build and emit a record for this declaration + Record.clear(); + W.Code = (pch::DeclCode)0; + W.AbbrevToUse = 0; + W.Visit(D); + if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); + + if (!W.Code) { + fprintf(stderr, "Cannot serialize declaration of kind %s\n", + D->getDeclKindName()); + assert(false && "Unhandled declaration kind while generating PCH"); + exit(-1); + } + Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); - // Flush any expressions that were written as part of this declaration. - FlushStmts(); + // If the declaration had any attributes, write them now. + if (D->hasAttrs()) + WriteAttributeRecord(D->getAttrs()); - // Note "external" declarations so that we can add them to a record in the - // PCH file later. - // - // FIXME: This should be renamed, the predicate is much more complicated. - if (isRequiredDecl(D, Context)) - ExternalDefinitions.push_back(ID); - } + // Flush any expressions that were written as part of this declaration. + FlushStmts(); - // Exit the declarations block - Stream.ExitBlock(); + // Note "external" declarations so that we can add them to a record in the + // PCH file later. + // + // FIXME: This should be renamed, the predicate is much more complicated. + if (isRequiredDecl(D, Context)) + ExternalDefinitions.push_back(Index + 1); } diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 492b31a0ec39..f3cb20619ed5 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -399,7 +399,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, } if (IdentifierInfo *II = Tok.getIdentifierInfo()) { - OS.write(II->getName(), II->getLength()); + OS << II->getName(); } else if (Tok.isLiteral() && !Tok.needsCleaning() && Tok.getLiteralData()) { OS.write(Tok.getLiteralData(), Tok.getLength()); @@ -434,7 +434,7 @@ namespace { struct SortMacrosByID { typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair; bool operator()(const id_macro_pair &LHS, const id_macro_pair &RHS) const { - return strcmp(LHS.first->getName(), RHS.first->getName()) < 0; + return LHS.first->getName() < RHS.first->getName(); } }; } diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp index d92f5c78e690..b5d59c0aa401 100644 --- a/lib/Frontend/RewriteMacros.cpp +++ b/lib/Frontend/RewriteMacros.cpp @@ -128,13 +128,13 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) { // comment the line out. if (RawTokens[CurRawTok].is(tok::identifier)) { const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo(); - if (!strcmp(II->getName(), "warning")) { + if (II->getName() == "warning") { // Comment out #warning. RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); - } else if (!strcmp(II->getName(), "pragma") && + } else if (II->getName() == "pragma" && RawTokens[CurRawTok+1].is(tok::identifier) && - !strcmp(RawTokens[CurRawTok+1].getIdentifierInfo()->getName(), - "mark")){ + (RawTokens[CurRawTok+1].getIdentifierInfo()->getName() == + "mark")) { // Comment out #pragma mark. RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); } diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 55ab78e638bb..0ea0a58d5239 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -675,7 +675,7 @@ static std::string getIvarAccessString(ObjCInterfaceDecl *ClassDecl, S = "((struct "; S += ClassDecl->getIdentifier()->getName(); S += "_IMPL *)self)->"; - S += OID->getNameAsCString(); + S += OID->getName(); return S; } @@ -2265,7 +2265,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { if (clsName) { // class message. // FIXME: We need to fix Sema (and the AST for ObjCMessageExpr) to handle // the 'super' idiom within a class method. - if (!strcmp(clsName->getName(), "super")) { + if (clsName->getName() == "super") { MsgSendFlavor = MsgSendSuperFunctionDecl; if (MsgSendStretFlavor) MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; @@ -2289,9 +2289,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, - SuperDecl->getIdentifier()->getName(), - SuperDecl->getIdentifier()->getLength(), - false, argType, SourceLocation())); + SuperDecl->getIdentifier()->getNameStart(), + SuperDecl->getIdentifier()->getLength(), + false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, &ClsExprs[0], ClsExprs.size()); @@ -2343,7 +2343,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getName(), + clsName->getNameStart(), clsName->getLength(), false, argType, SourceLocation())); @@ -2375,9 +2375,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, - SuperDecl->getIdentifier()->getName(), - SuperDecl->getIdentifier()->getLength(), - false, argType, SourceLocation())); + SuperDecl->getIdentifier()->getNameStart(), + SuperDecl->getIdentifier()->getLength(), + false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, &ClsExprs[0], ClsExprs.size()); diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 63d9a50b368b..14769c187393 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -214,6 +214,7 @@ static void SelectInterestingSourceRegion(std::string &SourceLine, // Move the end of the interesting region right until we've // pulled in something else interesting. if (CaretEnd != SourceLength) { + assert(CaretEnd < SourceLength && "Unexpected caret position!"); unsigned NewEnd = CaretEnd; // Skip over any whitespace we see here; we're looking for @@ -320,6 +321,11 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') ++LineEnd; + // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past + // the source line length as currently being computed. See + // test/Misc/message-length.c. + CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); + // Copy the line of code into an std::string for ease of manipulation. std::string SourceLine(LineStart, LineEnd); diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp index 6294d699a88c..c24f3bf5b3c1 100644 --- a/lib/Index/ASTLocation.cpp +++ b/lib/Index/ASTLocation.cpp @@ -101,7 +101,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const { break; case N_Type: { - QualType T = AsTypeLoc().getSourceType(); + QualType T = AsTypeLoc().getType(); OS << "[Type: " << T->getTypeClassName() << " " << T.getAsString(); } } diff --git a/lib/Index/ASTVisitor.h b/lib/Index/ASTVisitor.h index e18aa57b4d1a..0ae78fb74ff4 100644 --- a/lib/Index/ASTVisitor.h +++ b/lib/Index/ASTVisitor.h @@ -123,14 +123,14 @@ public: BaseTypeLocVisitor::Visit(TL); } - void VisitArrayLoc(ArrayLoc TL) { - BaseTypeLocVisitor::VisitArrayLoc(TL); + void VisitArrayLoc(ArrayTypeLoc TL) { + BaseTypeLocVisitor::VisitArrayTypeLoc(TL); if (TL.getSizeExpr()) Visit(TL.getSizeExpr()); } - void VisitFunctionLoc(FunctionLoc TL) { - BaseTypeLocVisitor::VisitFunctionLoc(TL); + void VisitFunctionTypeLoc(FunctionTypeLoc TL) { + BaseTypeLocVisitor::VisitFunctionTypeLoc(TL); for (unsigned i = 0; i != TL.getNumArgs(); ++i) Visit(TL.getArg(i)); } diff --git a/lib/Index/DeclReferenceMap.cpp b/lib/Index/DeclReferenceMap.cpp index 0e48a369d5d9..366cf1b10830 100644 --- a/lib/Index/DeclReferenceMap.cpp +++ b/lib/Index/DeclReferenceMap.cpp @@ -31,8 +31,8 @@ public: void VisitMemberExpr(MemberExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); - void VisitTypedefLoc(TypedefLoc TL); - void VisitObjCInterfaceLoc(ObjCInterfaceLoc TL); + void VisitTypedefTypeLoc(TypedefTypeLoc TL); + void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); }; } // anonymous namespace @@ -55,12 +55,12 @@ void RefMapper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { Map.insert(std::make_pair(Node->getDecl(), ASTLocation(CurrentDecl, Node))); } -void RefMapper::VisitTypedefLoc(TypedefLoc TL) { +void RefMapper::VisitTypedefTypeLoc(TypedefTypeLoc TL) { NamedDecl *ND = TL.getTypedefDecl(); Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc()))); } -void RefMapper::VisitObjCInterfaceLoc(ObjCInterfaceLoc TL) { +void RefMapper::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { NamedDecl *ND = TL.getIFaceDecl(); Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc()))); } diff --git a/lib/Index/Entity.cpp b/lib/Index/Entity.cpp index 77d7a84da4db..03fe9f73af40 100644 --- a/lib/Index/Entity.cpp +++ b/lib/Index/Entity.cpp @@ -72,7 +72,8 @@ Entity EntityGetter::VisitNamedDecl(NamedDecl *D) { if (IdentifierInfo *II = LocalName.getAsIdentifierInfo()) { IdentifierInfo *GlobII = - &ProgImpl.getIdents().get(II->getName(), II->getName() + II->getLength()); + &ProgImpl.getIdents().get(II->getNameStart(), + II->getNameStart() + II->getLength()); GlobName = DeclarationName(GlobII); } else { Selector LocalSel = LocalName.getObjCSelector(); @@ -139,8 +140,9 @@ Decl *EntityImpl::getDecl(ASTContext &AST) { DeclarationName LocalName; if (IdentifierInfo *GlobII = Name.getAsIdentifierInfo()) { - IdentifierInfo &II = AST.Idents.get(GlobII->getName(), - GlobII->getName() + GlobII->getLength()); + IdentifierInfo &II = + AST.Idents.get(GlobII->getNameStart(), + GlobII->getNameStart() + GlobII->getLength()); LocalName = DeclarationName(&II); } else { Selector GlobSel = Name.getObjCSelector(); diff --git a/lib/Index/GlobalSelector.cpp b/lib/Index/GlobalSelector.cpp index f3ec41d44ffe..2b2ca6d3b1cc 100644 --- a/lib/Index/GlobalSelector.cpp +++ b/lib/Index/GlobalSelector.cpp @@ -29,8 +29,9 @@ Selector GlobalSelector::getSelector(ASTContext &AST) const { for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs(); i != e; ++i) { IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i); - IdentifierInfo *II = &AST.Idents.get(GlobII->getName(), - GlobII->getName() + GlobII->getLength()); + IdentifierInfo *II = + &AST.Idents.get(GlobII->getNameStart(), + GlobII->getNameStart() + GlobII->getLength()); Ids.push_back(II); } @@ -57,8 +58,9 @@ GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) { for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs(); i != e; ++i) { IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i); - IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName(), - II->getName() + II->getLength()); + IdentifierInfo *GlobII = + &ProgImpl.getIdents().get(II->getNameStart(), + II->getNameStart() + II->getLength()); Ids.push_back(GlobII); } diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index 229669dc330b..8edd634f8af4 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -120,11 +120,12 @@ public: TypeLocResolver(ASTContext &ctx, SourceLocation loc, Decl *pd) : LocResolverBase(ctx, loc), ParentDecl(pd) { } - ASTLocation VisitTypedefLoc(TypedefLoc TL); - ASTLocation VisitFunctionLoc(FunctionLoc TL); - ASTLocation VisitArrayLoc(ArrayLoc TL); - ASTLocation VisitObjCInterfaceLoc(ObjCInterfaceLoc TL); - ASTLocation VisitObjCProtocolListLoc(ObjCProtocolListLoc TL); + ASTLocation VisitBuiltinTypeLoc(BuiltinTypeLoc TL); + ASTLocation VisitTypedefTypeLoc(TypedefTypeLoc TL); + ASTLocation VisitFunctionTypeLoc(FunctionTypeLoc TL); + ASTLocation VisitArrayTypeLoc(ArrayTypeLoc TL); + ASTLocation VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); + ASTLocation VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); ASTLocation VisitTypeLoc(TypeLoc TL); }; @@ -349,7 +350,25 @@ ASTLocation DeclLocResolver::VisitDecl(Decl *D) { return ASTLocation(D); } -ASTLocation TypeLocResolver::VisitTypedefLoc(TypedefLoc TL) { +ASTLocation TypeLocResolver::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + // Continue the 'id' magic by making the builtin type (which cannot + // actually be spelled) map to the typedef. + BuiltinType *T = TL.getTypePtr(); + if (T->getKind() == BuiltinType::ObjCId) { + TypedefDecl *D = Ctx.getObjCIdType()->getAs<TypedefType>()->getDecl(); + return ASTLocation(ParentDecl, D, TL.getNameLoc()); + } + + // Same thing with 'Class'. + if (T->getKind() == BuiltinType::ObjCClass) { + TypedefDecl *D = Ctx.getObjCClassType()->getAs<TypedefType>()->getDecl(); + return ASTLocation(ParentDecl, D, TL.getNameLoc()); + } + + return ASTLocation(ParentDecl, TL); +} + +ASTLocation TypeLocResolver::VisitTypedefTypeLoc(TypedefTypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); if (ContainsLocation(TL.getNameLoc())) @@ -357,7 +376,7 @@ ASTLocation TypeLocResolver::VisitTypedefLoc(TypedefLoc TL) { return ASTLocation(ParentDecl, TL); } -ASTLocation TypeLocResolver::VisitFunctionLoc(FunctionLoc TL) { +ASTLocation TypeLocResolver::VisitFunctionTypeLoc(FunctionTypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); @@ -373,7 +392,7 @@ ASTLocation TypeLocResolver::VisitFunctionLoc(FunctionLoc TL) { return ASTLocation(ParentDecl, TL); } -ASTLocation TypeLocResolver::VisitArrayLoc(ArrayLoc TL) { +ASTLocation TypeLocResolver::VisitArrayTypeLoc(ArrayTypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); @@ -384,17 +403,11 @@ ASTLocation TypeLocResolver::VisitArrayLoc(ArrayLoc TL) { return ASTLocation(ParentDecl, TL); } -ASTLocation TypeLocResolver::VisitObjCInterfaceLoc(ObjCInterfaceLoc TL) { +ASTLocation TypeLocResolver::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); if (ContainsLocation(TL.getNameLoc())) return ASTLocation(ParentDecl, TL.getIFaceDecl(), TL.getNameLoc()); - return ASTLocation(ParentDecl, TL); -} - -ASTLocation TypeLocResolver::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) { - assert(ContainsLocation(TL) && - "Should visit only after verifying that loc is in range"); for (unsigned i = 0; i != TL.getNumProtocols(); ++i) { SourceLocation L = TL.getProtocolLoc(i); @@ -408,6 +421,24 @@ ASTLocation TypeLocResolver::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) { return ASTLocation(ParentDecl, TL); } +ASTLocation TypeLocResolver::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + assert(ContainsLocation(TL) && + "Should visit only after verifying that loc is in range"); + + if (TL.hasProtocolsAsWritten()) { + for (unsigned i = 0; i != TL.getNumProtocols(); ++i) { + SourceLocation L = TL.getProtocolLoc(i); + RangePos RP = CheckRange(L); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return ASTLocation(ParentDecl, TL.getProtocol(i), L); + } + } + + return ASTLocation(ParentDecl, TL); +} + ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); @@ -497,9 +528,12 @@ void LocResolverBase::print(Stmt *Node) { /// \brief Returns the AST node that a source location points to. /// -ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) { +ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc, + Decl *RelativeToDecl) { if (Loc.isInvalid()) return ASTLocation(); + if (RelativeToDecl) + return DeclLocResolver(Ctx, Loc).Visit(RelativeToDecl); return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl()); } diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 196a77f6426a..e264efab9d7b 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -1071,7 +1071,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, // we allow macros that expand to nothing after the filename, because this // falls into the category of "#include pp-tokens new-line" specified in // C99 6.10.2p4. - CheckEndOfDirective(IncludeTok.getIdentifierInfo()->getName(), true); + CheckEndOfDirective(IncludeTok.getIdentifierInfo()->getNameStart(), true); // Check that we don't have infinite #include recursion. if (IncludeMacroStack.size() == MaxAllowedIncludeStackDepth-1) { diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp index 36ace8be7e06..f17a5d93a91a 100644 --- a/lib/Lex/PTHLexer.cpp +++ b/lib/Lex/PTHLexer.cpp @@ -20,8 +20,9 @@ #include "clang/Lex/PTHManager.h" #include "clang/Lex/Token.h" #include "clang/Lex/Preprocessor.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/MemoryBuffer.h" #include <sys/stat.h> using namespace clang; @@ -95,14 +96,6 @@ LexNextToken: //===--------------------------------------==// // Process the token. //===--------------------------------------==// -#if 0 - SourceManager& SM = PP->getSourceManager(); - llvm::errs() << SM.getFileEntryForID(FileID)->getName() - << ':' << SM.getLogicalLineNumber(Tok.getLocation()) - << ':' << SM.getLogicalColumnNumber(Tok.getLocation()) - << '\n'; -#endif - if (TKind == tok::eof) { // Save the end-of-file token. EofToken = Tok; @@ -308,7 +301,7 @@ public: typedef std::pair<unsigned char, const char*> internal_key_type; static unsigned ComputeHash(internal_key_type x) { - return BernsteinHash(x.second); + return llvm::HashString(x.second); } static std::pair<unsigned, unsigned> @@ -363,7 +356,7 @@ public: } static unsigned ComputeHash(const internal_key_type& a) { - return BernsteinHash(a.first, a.second); + return llvm::HashString(llvm::StringRef(a.first, a.second)); } // This hopefully will just get inlined and removed by the optimizer. @@ -562,7 +555,7 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) { // Store the new IdentifierInfo in the cache. PerIDCache[PersistentID] = II; - assert(II->getName() && II->getName()[0] != '\0'); + assert(II->getNameStart() && II->getNameStart()[0] != '\0'); return II; } @@ -679,7 +672,8 @@ public: CacheTy::iterator I = Cache.find(path); // If we don't get a hit in the PTH file just forward to 'stat'. - if (I == Cache.end()) return ::stat(path, buf); + if (I == Cache.end()) + return StatSysCallCache::stat(path, buf); const PTHStatData& Data = *I; diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index bfa090a09e87..7f3afc60764c 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -122,7 +122,7 @@ Preprocessor::~Preprocessor() { void Preprocessor::setPTHManager(PTHManager* pm) { PTH.reset(pm); - FileMgr.setStatCache(PTH->createStatCache()); + FileMgr.addStatCache(PTH->createStatCache()); } void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { @@ -234,7 +234,7 @@ unsigned Preprocessor::getSpelling(const Token &Tok, // If this token is an identifier, just return the string from the identifier // table, which is very quick. if (const IdentifierInfo *II = Tok.getIdentifierInfo()) { - Buffer = II->getName(); + Buffer = II->getNameStart(); return II->getLength(); } diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp index ade7f8516ea7..07951646ffe1 100644 --- a/lib/Lex/TokenConcatenation.cpp +++ b/lib/Lex/TokenConcatenation.cpp @@ -95,7 +95,7 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) { static char GetFirstChar(Preprocessor &PP, const Token &Tok) { if (IdentifierInfo *II = Tok.getIdentifierInfo()) { // Avoid spelling identifiers, the most common form of token. - return II->getName()[0]; + return II->getNameStart()[0]; } else if (!Tok.needsCleaning()) { if (Tok.isLiteral() && Tok.getLiteralData()) { return *Tok.getLiteralData(); diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 2ee41bc3eb8d..224a31cd5a5e 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -45,18 +45,15 @@ AttributeList::~AttributeList() { } AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { - const char *Str = Name->getName(); - unsigned Len = Name->getLength(); + llvm::StringRef AttrName = Name->getName(); // Normalize the attribute name, __foo__ becomes foo. - if (Len > 4 && Str[0] == '_' && Str[1] == '_' && - Str[Len - 2] == '_' && Str[Len - 1] == '_') { - Str += 2; - Len -= 4; - } + if (AttrName.startswith("__") && AttrName.endswith("__")) + AttrName = AttrName.substr(2, AttrName.size() - 4); // FIXME: Hand generating this is neither smart nor efficient. - switch (Len) { + const char *Str = AttrName.data(); + switch (AttrName.size()) { case 4: if (!memcmp(Str, "weak", 4)) return AT_weak; if (!memcmp(Str, "pure", 4)) return AT_pure; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 72e30e3b6079..8be89a891680 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -972,13 +972,41 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { return ExprError(); } - if (!LHS.isInvalid()) - LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), - OpLoc, OpKind, - Tok.getLocation(), - Tok.getIdentifierInfo(), - SS, - NextToken().is(tok::l_paren)); + if (NextToken().is(tok::less)) { + // class-name: + // ~ simple-template-id + TemplateTy Template + = Actions.ActOnDependentTemplateName(SourceLocation(), + *Tok.getIdentifierInfo(), + Tok.getLocation(), + SS, + ObjectType); + if (AnnotateTemplateIdToken(Template, TNK_Type_template, &SS, + SourceLocation(), true)) + return ExprError(); + + assert(Tok.is(tok::annot_typename) && + "AnnotateTemplateIdToken didn't work?"); + if (!LHS.isInvalid()) + LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), + OpLoc, OpKind, + Tok.getAnnotationRange(), + Tok.getAnnotationValue(), + SS, + NextToken().is(tok::l_paren)); + } else { + // class-name: + // ~ identifier + if (!LHS.isInvalid()) + LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), + OpLoc, OpKind, + Tok.getLocation(), + Tok.getIdentifierInfo(), + SS, + NextToken().is(tok::l_paren)); + } + + // Consume the identifier or template-id token. ConsumeToken(); } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) { // We have a reference to a member operator, e.g., t.operator int or diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 325f085a49d8..fa651569f8e1 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -356,7 +356,8 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { TemplateId->NumArgs); OwningExprResult Result - = Actions.ActOnTemplateIdExpr(TemplateTy::make(TemplateId->Template), + = Actions.ActOnTemplateIdExpr(SS, + TemplateTy::make(TemplateId->Template), TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 6ab23fd42ddc..c4e79cae3f54 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; @@ -65,9 +66,9 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { if (Tok.is(tok::identifier)) { const IdentifierInfo *FieldName = Tok.getIdentifierInfo(); - std::string NewSyntax("."); - NewSyntax += FieldName->getName(); - NewSyntax += " = "; + llvm::SmallString<256> NewSyntax; + llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName() + << " = "; SourceLocation NameLoc = ConsumeToken(); // Eat the identifier. @@ -77,7 +78,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { Diag(Tok, diag::ext_gnu_old_style_field_designator) << CodeModificationHint::CreateReplacement(SourceRange(NameLoc, ColonLoc), - NewSyntax); + NewSyntax.str()); Designation D; D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc)); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 1d29f319c584..2e0cd6d0d932 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -428,7 +428,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { return; } - if (II->getName()[0] == 's') { + if (II->getNameStart()[0] == 's') { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); DS.setSetterName(Tok.getIdentifierInfo()); ConsumeToken(); // consume method name @@ -1371,8 +1371,11 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { "parsing Objective-C method"); // parse optional ';' - if (Tok.is(tok::semi)) + if (Tok.is(tok::semi)) { + if (ObjCImpDecl) + Diag(Tok, diag::warn_semicolon_before_method_nody); ConsumeToken(); + } // We should have an opening brace now. if (Tok.isNot(tok::l_brace)) { diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 907ca802b4ae..272be2f66017 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1256,6 +1256,8 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { /// asm-string-literal '(' expression ')' /// '[' identifier ']' asm-string-literal '(' expression ')' /// +// +// FIXME: Avoid unnecessary std::string trashing. bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, llvm::SmallVectorImpl<ExprTy*> &Constraints, llvm::SmallVectorImpl<ExprTy*> &Exprs) { @@ -1281,7 +1283,7 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, IdentifierInfo *II = Tok.getIdentifierInfo(); ConsumeToken(); - Names.push_back(std::string(II->getName(), II->getLength())); + Names.push_back(II->getName()); MatchRHSPunctuation(tok::r_square, Loc); } else Names.push_back(std::string()); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 2f500a484da3..bc737e9f0c80 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -77,7 +77,10 @@ void PrettyStackTraceParserEntry::print(llvm::raw_ostream &OS) const { const Preprocessor &PP = P.getPreprocessor(); Tok.getLocation().print(OS, PP.getSourceManager()); - OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n"; + if (Tok.isAnnotation()) + OS << ": at annotation token \n"; + else + OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n"; } diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp index 30bbcfafb532..fdb6fc385ba1 100644 --- a/lib/Rewrite/RewriteRope.cpp +++ b/lib/Rewrite/RewriteRope.cpp @@ -154,6 +154,7 @@ namespace { ~RopePieceBTreeLeaf() { if (PrevLeaf || NextLeaf) removeFromLeafInOrder(); + clear(); } bool isFull() const { return NumPieces == 2*WidthFactor; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index ba05a07f2654..fc9c14f456bd 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -23,44 +23,134 @@ #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; + + // 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) { +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); - // If this is a sugared type (like a typedef, typeof, etc), then unwrap one - // level of the sugar so that the type is more obvious to the user. - QualType DesugaredTy = Ty.getDesugaredType(); - - if (Ty != DesugaredTy && - // 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". - !isa<VectorType>(DesugaredTy) && - - // Don't aka just because we saw an elaborated type... - (!isa<ElaboratedType>(Ty) || - cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) && - - // ...or a qualified name type... - (!isa<QualifiedNameType>(Ty) || - cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) && - - // ...or a non-dependent template specialization. - (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) && - - // Don't desugar magic Objective-C types. - Ty.getUnqualifiedType() != Context.getObjCIdType() && - Ty.getUnqualifiedType() != Context.getObjCClassType() && - Ty.getUnqualifiedType() != Context.getObjCSelType() && - Ty.getUnqualifiedType() != Context.getObjCProtoType() && - - // Not va_list. - Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { + // 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 += "')"; @@ -76,21 +166,27 @@ static std::string ConvertTypeToDiagnosticString(ASTContext &Context, 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; - if (Kind == Diagnostic::ak_qualtype) { + + 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); + S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs); NeedQuotes = false; - } else if (Kind == Diagnostic::ak_declarationname) { - + break; + } + case Diagnostic::ak_declarationname: { DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); S = N.getAsString(); @@ -101,7 +197,9 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, else assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); - } else if (Kind == Diagnostic::ak_nameddecl) { + break; + } + case Diagnostic::ak_nameddecl: { bool Qualified; if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) Qualified = true; @@ -110,30 +208,30 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, "Invalid modifier for NamedDecl* argument"); Qualified = false; } - reinterpret_cast<NamedDecl*>(Val)->getNameForDiagnostic(S, - Context.PrintingPolicy, - Qualified); - } else if (Kind == Diagnostic::ak_nestednamespec) { + 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); + reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS, + Context.PrintingPolicy); NeedQuotes = false; - } else { - assert(Kind == Diagnostic::ak_declcontext); + break; + } + case Diagnostic::ak_declcontext: { DeclContext *DC = reinterpret_cast<DeclContext *> (Val); - NeedQuotes = false; - if (!DC) { - assert(false && "Should never have a null declaration context"); - S = "unknown context"; - } else if (DC->isTranslationUnit()) { + 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)); - NeedQuotes = false; + S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type), + PrevArgs, NumPrevArgs); } else { // FIXME: Get these strings from some localized place NamedDecl *ND = cast<NamedDecl>(DC); @@ -147,8 +245,10 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, S += "'"; ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); S += "'"; - NeedQuotes = false; } + NeedQuotes = false; + break; + } } if (NeedQuotes) @@ -361,9 +461,8 @@ void Sema::ActOnEndOfTranslationUnit() { // Set the length of the array to 1 (C99 6.9.2p5). Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true); - QualType T - = Context.getConstantArrayWithoutExprType(ArrayT->getElementType(), - One, ArrayType::Normal, 0); + QualType T = Context.getConstantArrayType(ArrayT->getElementType(), + One, ArrayType::Normal, 0); VD->setType(T); } else if (RequireCompleteType(VD->getLocation(), VD->getType(), diag::err_tentative_def_incomplete_type)) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 80f366302171..6dd081bdc25e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -448,7 +448,7 @@ public: // QualType adjustParameterType(QualType T); QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, - bool &IsInvalid, QualType &SourceTy); + bool &IsInvalid); void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL); QualType BuildPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); @@ -908,6 +908,7 @@ public: bool IsAssignmentOperator = false, unsigned NumContextualBoolArguments = 0); void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, @@ -929,7 +930,7 @@ public: FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); - void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); void AddOverloadedCallCandidates(NamedDecl *Callee, DeclarationName &UnqualifiedName, @@ -2108,6 +2109,15 @@ public: bool HasTrailingLParen); virtual OwningExprResult + ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceRange TypeRange, + TypeTy *Type, + const CXXScopeSpec &SS, + bool HasTrailingLParen); + + virtual OwningExprResult ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, @@ -2343,6 +2353,10 @@ public: FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); + bool isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, + SourceLocation NameLoc, QualType &ThisType, + QualType &MemberType); + //===--------------------------------------------------------------------===// // C++ Derived Classes // @@ -2515,14 +2529,17 @@ public: DeclSpec::TST TagSpec, SourceLocation TagLoc); - OwningExprResult BuildTemplateIdExpr(TemplateName Template, + OwningExprResult BuildTemplateIdExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); - virtual OwningExprResult ActOnTemplateIdExpr(TemplateTy Template, + virtual OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS, + TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, @@ -3143,6 +3160,10 @@ public: void PerformPendingImplicitInstantiations(); + DeclaratorInfo *SubstType(DeclaratorInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + QualType SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); @@ -3197,11 +3218,13 @@ public: void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, - bool Recursive = false); + bool Recursive = false, + bool DefinitionRequired = false); void InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, - bool Recursive = false); + bool Recursive = false, + bool DefinitionRequired = false); void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, @@ -3404,8 +3427,7 @@ public: /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. - void ImpCastExprToType(Expr *&Expr, QualType Type, - CastExpr::CastKind Kind = CastExpr::CK_Unknown, + void ImpCastExprToType(Expr *&Expr, QualType Type, CastExpr::CastKind Kind, bool isLvalue = false); // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts @@ -3550,6 +3572,10 @@ public: bool PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, const char *Flavor); + + bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, + const ImplicitConversionSequence& ICS, + const char *Flavor); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). @@ -3659,14 +3685,16 @@ public: // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size. // returns true if the cast is invalid - bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty); + bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, + CastExpr::CastKind &Kind); // CheckExtVectorCast - check type constraints for extended vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size, // or vectors and the element type of that vector. // returns true if the cast is invalid - bool CheckExtVectorCast(SourceRange R, QualType VectorTy, QualType Ty); + bool CheckExtVectorCast(SourceRange R, QualType VectorTy, Expr *&CastExpr, + CastExpr::CastKind &Kind); /// CXXCheckCStyleCast - Check constraints of a C-style or function-style /// cast under C++ semantics. @@ -3727,22 +3755,6 @@ public: QualType FieldTy, const Expr *BitWidth, bool *ZeroWidth = 0); - /// adjustFunctionParamType - Converts the type of a function parameter to a - // type that can be passed as an argument type to - /// ASTContext::getFunctionType. - /// - /// C++ [dcl.fct]p3: "...Any cv-qualifier modifying a parameter type is - /// deleted. Such cv-qualifiers affect only the definition of the parameter - /// within the body of the function; they do not affect the function type. - QualType adjustFunctionParamType(QualType T) const { - if (!Context.getLangOptions().CPlusPlus) - return T; - return - T->isDependentType() ? T.getUnqualifiedType() - : T.getDesugaredType().getUnqualifiedType(); - - } - /// \name Code completion //@{ void setCodeCompleteConsumer(CodeCompleteConsumer *CCC); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 69d1f92a0832..bf396041b473 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -175,7 +175,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, /// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by /// the cast checkers. Both arguments must denote pointer (possibly to member) /// types. -bool +static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { // Casting away constness is defined in C++ 5.2.11p8 with reference to // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since @@ -605,6 +605,11 @@ TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, QualType OrigDestType, unsigned &msg) { + // We can only work with complete types. But don't complain if it doesn't work + if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, PDiag(0)) || + Self.RequireCompleteType(OpRange.getBegin(), DestType, PDiag(0))) + return TC_NotApplicable; + // Downcast can only happen in class hierarchies, so we need classes. if (!DestType->isRecordType() || !SrcType->isRecordType()) { return TC_NotApplicable; @@ -943,6 +948,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, } // A valid member pointer cast. + Kind = CastExpr::CK_BitCast; return TC_Success; } @@ -1044,6 +1050,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // Not casting away constness, so the only remaining check is for compatible // pointer categories. + Kind = CastExpr::CK_BitCast; if (SrcType->isFunctionPointerType()) { if (DestType->isFunctionPointerType()) { @@ -1085,8 +1092,10 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". - if (CastTy->isVoidType()) + if (CastTy->isVoidType()) { + Kind = CastExpr::CK_ToVoid; return false; + } // If the type is dependent, we won't do any other semantic analysis now. if (CastTy->isDependentType() || CastExpr->isTypeDependent()) @@ -1109,6 +1118,9 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, unsigned msg = diag::err_bad_cxx_cast_generic; TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true, msg); + if (tcr == TC_Success) + Kind = CastExpr::CK_NoOp; + if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 92bf83f0830d..589b0c6bd0ec 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -381,8 +381,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // If the first type needs to be converted (e.g. void** -> int*), do it now. if (BuiltinFT->getArgType(0) != FirstArg->getType()) { - ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), CastExpr::CK_Unknown, - /*isLvalue=*/false); + ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), CastExpr::CK_BitCast); TheCall->setArg(0, FirstArg); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 3981b8d22fa3..381151325a03 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -235,8 +235,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // Filter out names reserved for the implementation (C99 7.1.3, // C++ [lib.global.names]). Users don't need to see those. + // + // FIXME: Add predicate for this. if (Id->getLength() >= 2) { - const char *Name = Id->getName(); + const char *Name = Id->getNameStart(); if (Name[0] == '_' && (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z'))) return; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 606b33f5f74b..b83181becb93 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -218,7 +218,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, << &II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { Diag(SS->getRange().getBegin(), diag::err_typename_missing) - << (NestedNameSpecifier *)SS->getScopeRep() << II.getName() + << (NestedNameSpecifier *)SS->getScopeRep() << II.getName() << SourceRange(SS->getRange().getBegin(), IILoc) << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(), "typename "); @@ -1059,6 +1059,8 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { /// NeverFallThrough iff we never fall off the end of the statement. We assume /// that functions not marked noreturn will return. Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { + // FIXME: Eventually share this CFG object when we have other warnings based + // of the CFG. This can be done using AnalysisContext. llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context)); // FIXME: They should never return 0, fix that, delete this code. @@ -1527,14 +1529,19 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; } + // Mock up a declarator. + Declarator Dc(DS, Declarator::TypeNameContext); + DeclaratorInfo *DInfo = 0; + GetTypeForDeclarator(Dc, S, &DInfo); + assert(DInfo && "couldn't build declarator info for anonymous struct/union"); + // Create a declaration for this anonymous struct/union. NamedDecl *Anon = 0; if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) { Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - // FIXME: Type source info. - /*DInfo=*/0, + DInfo, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS_public); if (getLangOptions().CPlusPlus) @@ -1561,8 +1568,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Anon = VarDecl::Create(Context, Owner, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - // FIXME: Type source info. - /*DInfo=*/0, + DInfo, SC); } Anon->setImplicit(); @@ -1903,16 +1909,9 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, llvm::APSInt &Res = EvalResult.Val.getInt(); if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) { - Expr* ArySizeExpr = VLATy->getSizeExpr(); - // FIXME: here we could "steal" (how?) ArySizeExpr from the VLA, - // so as to transfer ownership to the ConstantArrayWithExpr. - // Alternatively, we could "clone" it (how?). - // Since we don't know how to do things above, we just use the - // very same Expr*. - return Context.getConstantArrayWithExprType(VLATy->getElementType(), - Res, ArySizeExpr, - ArrayType::Normal, 0, - VLATy->getBracketsRange()); + // TODO: preserve the size expression in declarator info + return Context.getConstantArrayType(VLATy->getElementType(), + Res, ArrayType::Normal, 0); } SizeIsNegative = true; @@ -3331,7 +3330,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { << Init->getSourceRange(); VDecl->setInvalidDecl(); } else if (!VDecl->getType()->isDependentType()) - ImpCastExprToType(Init, VDecl->getType()); + ImpCastExprToType(Init, VDecl->getType(), CastExpr::CK_IntegralCast); } } } else if (VDecl->isFileVarDecl()) { @@ -3534,10 +3533,37 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, // 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 (!IDecl->isInvalidDecl() && - RequireCompleteType(IDecl->getLocation(), T, - diag::err_typecheck_decl_incomplete_type)) - IDecl->setInvalidDecl(); + 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 = T->getAs<IncompleteArrayType>(); + 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 @@ -3707,12 +3733,13 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, for (int i = FTI.NumArgs; i != 0; /* decrement in loop */) { --i; if (FTI.ArgInfo[i].Param == 0) { - std::string Code = " int "; - Code += FTI.ArgInfo[i].Ident->getName(); - Code += ";\n"; + llvm::SmallString<256> Code; + llvm::raw_svector_ostream(Code) << " int " + << FTI.ArgInfo[i].Ident->getName() + << ";\n"; Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared) << FTI.ArgInfo[i].Ident - << CodeModificationHint::CreateInsertion(LocAfterDecls, Code); + << CodeModificationHint::CreateInsertion(LocAfterDecls, Code.str()); // Implicitly declare the argument as type 'int' for lack of a better // type. @@ -3975,9 +4002,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, } // Extension in C99. Legal in C90, but warn about it. - static const unsigned int BuiltinLen = strlen("__builtin_"); - if (II.getLength() > BuiltinLen && - std::equal(II.getName(), II.getName() + BuiltinLen, "__builtin_")) + if (II.getName().startswith("__builtin_")) Diag(Loc, diag::warn_builtin_unknown) << &II; else if (getLangOptions().C99) Diag(Loc, diag::ext_implicit_function_decl) << &II; @@ -5587,7 +5612,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Adjust the Expr initializer and type. if (ECD->getInitExpr()) ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, - CastExpr::CK_Unknown, + CastExpr::CK_IntegralCast, ECD->getInitExpr(), /*isLvalue=*/false)); if (getLangOptions().CPlusPlus) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 50ebb49e7d5b..341d49ead418 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1202,6 +1202,35 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue())); } +enum FormatAttrKind { + CFStringFormat, + NSStringFormat, + StrftimeFormat, + SupportedFormat, + InvalidFormat +}; + +/// getFormatAttrKind - Map from format attribute names to supported format +/// types. +static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) { + // Check for formats that get handled specially. + if (Format == "NSString") + return NSStringFormat; + if (Format == "CFString") + return CFStringFormat; + if (Format == "strftime") + return StrftimeFormat; + + // Otherwise, check for supported formats. + if (Format == "scanf" || Format == "printf" || Format == "printf0" || + Format == "strfmon" || Format == "cmn_err" || Format == "strftime" || + Format == "NSString" || Format == "CFString" || Format == "vcmn_err" || + Format == "zcmn_err") + return SupportedFormat; + + return InvalidFormat; +} + /// Handle __attribute__((format(type,idx,firstarg))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1226,38 +1255,15 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { unsigned NumArgs = getFunctionOrMethodNumArgs(d); unsigned FirstIdx = 1; - const char *Format = Attr.getParameterName()->getName(); - unsigned FormatLen = Attr.getParameterName()->getLength(); + llvm::StringRef Format = Attr.getParameterName()->getName(); // Normalize the argument, __foo__ becomes foo. - if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' && - Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') { - Format += 2; - FormatLen -= 4; - } - - bool Supported = false; - bool is_NSString = false; - bool is_strftime = false; - bool is_CFString = false; - - switch (FormatLen) { - default: break; - case 5: Supported = !memcmp(Format, "scanf", 5); break; - case 6: Supported = !memcmp(Format, "printf", 6); break; - case 7: Supported = !memcmp(Format, "printf0", 7) || - !memcmp(Format, "strfmon", 7) || - !memcmp(Format, "cmn_err", 7); break; - case 8: - Supported = (is_strftime = !memcmp(Format, "strftime", 8)) || - (is_NSString = !memcmp(Format, "NSString", 8)) || - !memcmp(Format, "vcmn_err", 8) || - !memcmp(Format, "zcmn_err", 8) || - (is_CFString = !memcmp(Format, "CFString", 8)); - break; - } + if (Format.startswith("__") && Format.endswith("__")) + Format = Format.substr(2, Format.size() - 4); - if (!Supported) { + // Check for supported formats. + FormatAttrKind Kind = getFormatAttrKind(Format); + if (Kind == InvalidFormat) { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "format" << Attr.getParameterName()->getName(); return; @@ -1296,13 +1302,13 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // make sure the format string is really a string QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); - if (is_CFString) { + if (Kind == CFStringFormat) { if (!isCFStringType(Ty, S.Context)) { S.Diag(Attr.getLoc(), diag::err_format_attribute_not) << "a CFString" << IdxExpr->getSourceRange(); return; } - } else if (is_NSString) { + } else if (Kind == NSStringFormat) { // FIXME: do we need to check if the type is NSString*? What are the // semantics? if (!isNSStringType(Ty, S.Context)) { @@ -1340,7 +1346,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // strftime requires FirstArg to be 0 because it doesn't read from any // variable the input is just the current time + the format string. - if (is_strftime) { + if (Kind == StrftimeFormat) { if (FirstArg != 0) { S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter) << FirstArgExpr->getSourceRange(); @@ -1353,8 +1359,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) FormatAttr(std::string(Format, FormatLen), - Idx.getZExtValue(), FirstArg.getZExtValue())); + d->addAttr(::new (S.Context) FormatAttr(Format, Idx.getZExtValue(), + FirstArg.getZExtValue())); } static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, @@ -1496,20 +1502,17 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_missing_parameter_name); return; } - const char *Str = Name->getName(); - unsigned Len = Name->getLength(); + + llvm::StringRef Str = Attr.getParameterName()->getName(); // Normalize the attribute name, __foo__ becomes foo. - if (Len > 4 && Str[0] == '_' && Str[1] == '_' && - Str[Len - 2] == '_' && Str[Len - 1] == '_') { - Str += 2; - Len -= 4; - } + if (Str.startswith("__") && Str.endswith("__")) + Str = Str.substr(2, Str.size() - 4); unsigned DestWidth = 0; bool IntegerMode = true; bool ComplexMode = false; - switch (Len) { + switch (Str.size()) { case 2: switch (Str[0]) { case 'Q': DestWidth = 8; break; @@ -1531,13 +1534,13 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { case 4: // FIXME: glibc uses 'word' to define register_t; this is narrower than a // pointer on PIC16 and other embedded platforms. - if (!memcmp(Str, "word", 4)) + if (Str == "word") DestWidth = S.Context.Target.getPointerWidth(0); - if (!memcmp(Str, "byte", 4)) + else if (Str == "byte") DestWidth = S.Context.Target.getCharWidth(); break; case 7: - if (!memcmp(Str, "pointer", 7)) + if (Str == "pointer") DestWidth = S.Context.Target.getPointerWidth(0); break; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 419c8a13c2d4..6d1f4ea4a865 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1658,12 +1658,10 @@ namespace { // Traverse the record, looking for methods. if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) { // If the method is pure virtual, add it to the methods vector. - if (MD->isPure()) { + if (MD->isPure()) Methods.push_back(MD); - continue; - } - // Otherwise, record all the overridden methods in our set. + // Record all the overridden methods in our set. for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { // Keep track of the overridden methods. @@ -3571,7 +3569,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (DiagnoseUseOfDecl(Fn, DeclLoc)) return true; - FixOverloadedFunctionReference(Init, Fn); + Init = FixOverloadedFunctionReference(Init, Fn); } T2 = Fn->getType(); @@ -3660,7 +3658,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // applicable conversion functions (13.3.1.6) and choosing // the best one through overload resolution (13.3)), if (!isRValRef && !SuppressUserConversions && T2->isRecordType() && - !RequireCompleteType(SourceLocation(), T2, 0)) { + !RequireCompleteType(DeclLoc, T2, 0)) { CXXRecordDecl *T2RecordDecl = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); @@ -4283,8 +4281,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. bool invalid = false; - QualType SourceTy; - QualType T = ConvertDeclSpecToType(DS, Loc, invalid, SourceTy); + QualType T = ConvertDeclSpecToType(DS, Loc, invalid); if (invalid) return DeclPtrTy(); // This is definitely an error in C++98. It's probably meant to diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index a946500660e8..ae45429952c7 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -241,12 +241,12 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) { // other types are unchanged by the integer promotions. QualType PTy = Context.isPromotableBitField(Expr); if (!PTy.isNull()) { - ImpCastExprToType(Expr, PTy); + ImpCastExprToType(Expr, PTy, CastExpr::CK_IntegralCast); return Expr; } if (Ty->isPromotableIntegerType()) { QualType PT = Context.getPromotedIntegerType(Ty); - ImpCastExprToType(Expr, PT); + ImpCastExprToType(Expr, PT, CastExpr::CK_IntegralCast); return Expr; } @@ -264,7 +264,8 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { // If this is a 'float' (CVR qualified or typedef) promote to double. if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) if (BT->getKind() == BuiltinType::Float) - return ImpCastExprToType(Expr, Context.DoubleTy); + return ImpCastExprToType(Expr, Context.DoubleTy, + CastExpr::CK_FloatingCast); UsualUnaryConversions(Expr); } @@ -330,8 +331,8 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs); if (!isCompAssign) - ImpCastExprToType(lhsExpr, destType); - ImpCastExprToType(rhsExpr, destType); + ImpCastExprToType(lhsExpr, destType, CastExpr::CK_Unknown); + ImpCastExprToType(rhsExpr, destType, CastExpr::CK_Unknown); return destType; } @@ -940,95 +941,31 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, // We may have found a field within an anonymous union or struct // (C++ [class.union]). + // FIXME: This needs to happen post-isImplicitMemberReference? if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion()) return BuildAnonymousStructUnionMemberReference(Loc, FD); - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { - if (!MD->isStatic()) { - // C++ [class.mfct.nonstatic]p2: - // [...] if name lookup (3.4.1) resolves the name in the - // id-expression to a nonstatic nontype member of class X or of - // a base class of X, the id-expression is transformed into a - // class member access expression (5.2.5) using (*this) (9.3.2) - // as the postfix-expression to the left of the '.' operator. - DeclContext *Ctx = 0; - QualType MemberType; - if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { - Ctx = FD->getDeclContext(); - MemberType = FD->getType(); - - if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>()) - MemberType = RefType->getPointeeType(); - else if (!FD->isMutable()) - MemberType - = Context.getQualifiedType(MemberType, - Qualifiers::fromCVRMask(MD->getTypeQualifiers())); - } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - if (!Method->isStatic()) { - Ctx = Method->getParent(); - MemberType = Method->getType(); - } - } else if (FunctionTemplateDecl *FunTmpl - = dyn_cast<FunctionTemplateDecl>(D)) { - if (CXXMethodDecl *Method - = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())) { - if (!Method->isStatic()) { - Ctx = Method->getParent(); - MemberType = Context.OverloadTy; - } - } - } else if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(D)) { - // FIXME: We need an abstraction for iterating over one or more function - // templates or functions. This code is far too repetitive! - for (OverloadedFunctionDecl::function_iterator - Func = Ovl->function_begin(), - FuncEnd = Ovl->function_end(); - Func != FuncEnd; ++Func) { - CXXMethodDecl *DMethod = 0; - if (FunctionTemplateDecl *FunTmpl - = dyn_cast<FunctionTemplateDecl>(*Func)) - DMethod = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); - else - DMethod = dyn_cast<CXXMethodDecl>(*Func); - - if (DMethod && !DMethod->isStatic()) { - Ctx = DMethod->getDeclContext(); - MemberType = Context.OverloadTy; - break; - } - } - } - - if (Ctx && Ctx->isRecord()) { - QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx)); - QualType ThisType = Context.getTagDeclType(MD->getParent()); - if ((Context.getCanonicalType(CtxType) - == Context.getCanonicalType(ThisType)) || - IsDerivedFrom(ThisType, CtxType)) { - // Build the implicit member access expression. - Expr *This = new (Context) CXXThisExpr(SourceLocation(), - MD->getThisType(Context)); - MarkDeclarationReferenced(Loc, D); - if (PerformObjectMemberConversion(This, D)) - return ExprError(); - - bool ShouldCheckUse = true; - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { - // Don't diagnose the use of a virtual member function unless it's - // explicitly qualified. - if (MD->isVirtual() && (!SS || !SS->isSet())) - ShouldCheckUse = false; - } + // Cope with an implicit member access in a C++ non-static member function. + QualType ThisType, MemberType; + if (isImplicitMemberReference(SS, D, Loc, ThisType, MemberType)) { + Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); + MarkDeclarationReferenced(Loc, D); + if (PerformObjectMemberConversion(This, D)) + return ExprError(); - if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc)) - return ExprError(); - return Owned(BuildMemberExpr(Context, This, true, SS, D, - Loc, MemberType)); - } - } + bool ShouldCheckUse = true; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + // Don't diagnose the use of a virtual member function unless it's + // explicitly qualified. + if (MD->isVirtual() && (!SS || !SS->isSet())) + ShouldCheckUse = false; } + + if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc)) + return ExprError(); + return Owned(BuildMemberExpr(Context, This, true, SS, D, + Loc, MemberType)); } if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { @@ -1813,7 +1750,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, // force the promotion here. Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << LHSExp->getSourceRange(); - ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy)); + ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy), + CastExpr::CK_ArrayToPointerDecay); LHSTy = LHSExp->getType(); BaseExpr = LHSExp; @@ -1823,7 +1761,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, // Same as previous, except for 123[f().a] case Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << RHSExp->getSourceRange(); - ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy)); + ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy), + CastExpr::CK_ArrayToPointerDecay); RHSTy = RHSExp->getType(); BaseExpr = RHSExp; @@ -1877,10 +1816,15 @@ QualType Sema:: CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, const IdentifierInfo *CompName, SourceLocation CompLoc) { + // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements, + // see FIXME there. + // + // FIXME: This logic can be greatly simplified by splitting it along + // halving/not halving and reworking the component checking. const ExtVectorType *vecType = baseType->getAs<ExtVectorType>(); // The vector accessor can't exceed the number of elements. - const char *compStr = CompName->getName(); + const char *compStr = CompName->getNameStart(); // This flag determines whether or not the component is one of the four // special names that indicate a subset of exactly half the elements are @@ -1917,7 +1861,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, // Ensure no component accessor exceeds the width of the vector type it // operates on. if (!HalvingSwizzle) { - compStr = CompName->getName(); + compStr = CompName->getNameStart(); if (HexSwizzle) compStr++; @@ -2042,7 +1986,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // is a reference to 'isa'. if (BaseType != Context.ObjCIdRedefinitionType) { BaseType = Context.ObjCIdRedefinitionType; - ImpCastExprToType(BaseExpr, BaseType); + ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); } } assert(!BaseType.isNull() && "no type for member expression"); @@ -2100,7 +2044,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, if (BaseType->isObjCClassType() && BaseType != Context.ObjCClassRedefinitionType) { BaseType = Context.ObjCClassRedefinitionType; - ImpCastExprToType(BaseExpr, BaseType); + ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); } // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr @@ -2184,6 +2128,12 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // If the member name was a qualified-id, look into the // nested-name-specifier. DC = computeDeclContext(*SS, false); + + if (!isa<TypeDecl>(DC)) { + Diag(MemberLoc, diag::err_qualified_member_nonclass) + << DC << SS->getRange(); + return ExprError(); + } // FIXME: If DC is not computable, we should build a // CXXUnresolvedMemberExpr. @@ -3142,6 +3092,40 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, return Owned(E); } +static CastExpr::CastKind getScalarCastKind(ASTContext &Context, + QualType SrcTy, QualType DestTy) { + if (Context.getCanonicalType(SrcTy).getUnqualifiedType() == + Context.getCanonicalType(DestTy).getUnqualifiedType()) + return CastExpr::CK_NoOp; + + if (SrcTy->hasPointerRepresentation()) { + if (DestTy->hasPointerRepresentation()) + return CastExpr::CK_BitCast; + if (DestTy->isIntegerType()) + return CastExpr::CK_PointerToIntegral; + } + + if (SrcTy->isIntegerType()) { + if (DestTy->isIntegerType()) + return CastExpr::CK_IntegralCast; + if (DestTy->hasPointerRepresentation()) + return CastExpr::CK_IntegralToPointer; + if (DestTy->isRealFloatingType()) + return CastExpr::CK_IntegralToFloating; + } + + if (SrcTy->isRealFloatingType()) { + if (DestTy->isRealFloatingType()) + return CastExpr::CK_FloatingCast; + if (DestTy->isIntegerType()) + return CastExpr::CK_FloatingToIntegral; + } + + // FIXME: Assert here. + // assert(false && "Unhandled cast combination!"); + return CastExpr::CK_Unknown; +} + /// CheckCastTypes - Check type constraints for casting between types. bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, CastExpr::CastKind& Kind, @@ -3157,7 +3141,11 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, // type needs to be scalar. if (castType->isVoidType()) { // Cast to void allows any expr type. - } else if (!castType->isScalarType() && !castType->isVectorType()) { + Kind = CastExpr::CK_ToVoid; + return false; + } + + if (!castType->isScalarType() && !castType->isVectorType()) { if (Context.getCanonicalType(castType).getUnqualifiedType() == Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) && (castType->isStructureType() || castType->isUnionType())) { @@ -3166,7 +3154,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) << castType << castExpr->getSourceRange(); Kind = CastExpr::CK_NoOp; - } else if (castType->isUnionType()) { + return false; + } + + if (castType->isUnionType()) { // GCC cast to union extension RecordDecl *RD = castType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator Field, FieldEnd; @@ -3183,28 +3174,36 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) << castExpr->getType() << castExpr->getSourceRange(); Kind = CastExpr::CK_ToUnion; - } else { - // Reject any other conversions to non-scalar types. - return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) - << castType << castExpr->getSourceRange(); + return false; } - } else if (!castExpr->getType()->isScalarType() && - !castExpr->getType()->isVectorType()) { + + // Reject any other conversions to non-scalar types. + return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) + << castType << castExpr->getSourceRange(); + } + + if (!castExpr->getType()->isScalarType() && + !castExpr->getType()->isVectorType()) { return Diag(castExpr->getLocStart(), diag::err_typecheck_expect_scalar_operand) << castExpr->getType() << castExpr->getSourceRange(); - } else if (castType->isExtVectorType()) { - if (CheckExtVectorCast(TyR, castType, castExpr->getType())) - return true; - } else if (castType->isVectorType()) { - if (CheckVectorCast(TyR, castType, castExpr->getType())) - return true; - } else if (castExpr->getType()->isVectorType()) { - if (CheckVectorCast(TyR, castExpr->getType(), castType)) - return true; - } else if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) { + } + + if (castType->isExtVectorType()) + return CheckExtVectorCast(TyR, castType, castExpr, Kind); + + if (castType->isVectorType()) + return CheckVectorCast(TyR, castType, castExpr->getType(), Kind); + if (castExpr->getType()->isVectorType()) + return CheckVectorCast(TyR, castExpr->getType(), castType, Kind); + + if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR; - } else if (!castType->isArithmeticType()) { + + if (isa<ObjCSelectorExpr>(castExpr)) + return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); + + if (!castType->isArithmeticType()) { QualType castExprType = castExpr->getType(); if (!castExprType->isIntegralType() && castExprType->isArithmeticType()) return Diag(castExpr->getLocStart(), @@ -3216,12 +3215,13 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, diag::err_cast_pointer_to_non_pointer_int) << castType << castExpr->getSourceRange(); } - if (isa<ObjCSelectorExpr>(castExpr)) - return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); + + Kind = getScalarCastKind(Context, castExpr->getType(), castType); return false; } -bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) { +bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, + CastExpr::CastKind &Kind) { assert(VectorTy->isVectorType() && "Not a vector type!"); if (Ty->isVectorType() || Ty->isIntegerType()) { @@ -3236,18 +3236,23 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) { diag::err_invalid_conversion_between_vector_and_scalar) << VectorTy << Ty << R; + Kind = CastExpr::CK_BitCast; return false; } -bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) { +bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, + CastExpr::CastKind &Kind) { assert(DestTy->isExtVectorType() && "Not an extended vector type!"); - + + QualType SrcTy = CastExpr->getType(); + // If SrcTy is a VectorType, the total size must match to explicitly cast to // an ExtVectorType. if (SrcTy->isVectorType()) { if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)) return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) << DestTy << SrcTy << R; + Kind = CastExpr::CK_BitCast; return false; } @@ -3258,6 +3263,12 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) { return Diag(R.getBegin(), diag::err_invalid_conversion_between_vector_and_scalar) << DestTy << SrcTy << R; + + QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType(); + ImpCastExprToType(CastExpr, DestElemTy, + getScalarCastKind(Context, SrcTy, DestElemTy)); + + Kind = CastExpr::CK_VectorSplat; return false; } @@ -3414,20 +3425,21 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!RHSTy->isVoidType()) Diag(LHS->getLocStart(), diag::ext_typecheck_cond_one_void) << LHS->getSourceRange(); - ImpCastExprToType(LHS, Context.VoidTy); - ImpCastExprToType(RHS, Context.VoidTy); + ImpCastExprToType(LHS, Context.VoidTy, CastExpr::CK_ToVoid); + ImpCastExprToType(RHS, Context.VoidTy, CastExpr::CK_ToVoid); return Context.VoidTy; } // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) && RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer. + // promote the null to a pointer. + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_Unknown); return LHSTy; } if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) && LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer. + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown); return RHSTy; } // Handle things like Class and struct objc_class*. Here we case the result @@ -3435,23 +3447,23 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // redefinition type if an attempt is made to access its fields. if (LHSTy->isObjCClassType() && (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy); + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } if (RHSTy->isObjCClassType() && (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy); + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); return RHSTy; } // And the same for struct objc_object* / id if (LHSTy->isObjCIdType() && (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy); + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } if (RHSTy->isObjCIdType() && (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy); + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); return RHSTy; } // Handle block pointer types. @@ -3459,8 +3471,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { QualType destType = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, destType); - ImpCastExprToType(RHS, destType); + ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); return destType; } Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) @@ -3484,13 +3496,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, incompatTy); - ImpCastExprToType(RHS, incompatTy); + ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); return incompatTy; } // The block pointer types are compatible. - ImpCastExprToType(LHS, LHSTy); - ImpCastExprToType(RHS, LHSTy); + ImpCastExprToType(LHS, LHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } // Check constraints for Objective-C object pointers types. @@ -3536,13 +3548,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); QualType incompatTy = Context.getObjCIdType(); - ImpCastExprToType(LHS, incompatTy); - ImpCastExprToType(RHS, incompatTy); + ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); return incompatTy; } // The object pointer types are compatible. - ImpCastExprToType(LHS, compositeType); - ImpCastExprToType(RHS, compositeType); + ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast); return compositeType; } // Check Objective-C object pointer types and 'void *' @@ -3552,8 +3564,10 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, QualType destPointee = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(LHS, destType); // add qualifiers if necessary - ImpCastExprToType(RHS, destType); // promote to void* + // Add qualifiers if necessary. + ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); return destType; } if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { @@ -3562,8 +3576,10 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, QualType destPointee = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(RHS, destType); // add qualifiers if necessary - ImpCastExprToType(LHS, destType); // promote to void* + // Add qualifiers if necessary. + ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); return destType; } // Check constraints for C object pointers types (C99 6.5.15p3,6). @@ -3578,16 +3594,20 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, QualType destPointee = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(LHS, destType); // add qualifiers if necessary - ImpCastExprToType(RHS, destType); // promote to void* + // Add qualifiers if necessary. + ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); return destType; } if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { QualType destPointee = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(LHS, destType); // add qualifiers if necessary - ImpCastExprToType(RHS, destType); // promote to void* + // Add qualifiers if necessary. + ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); return destType; } @@ -3603,8 +3623,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, incompatTy); - ImpCastExprToType(RHS, incompatTy); + ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); return incompatTy; } // The pointer types are compatible. @@ -3614,8 +3634,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // type. // FIXME: Need to calculate the composite type. // FIXME: Need to add qualifiers - ImpCastExprToType(LHS, LHSTy); - ImpCastExprToType(RHS, LHSTy); + ImpCastExprToType(LHS, LHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } @@ -3623,13 +3643,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (RHSTy->isPointerType() && LHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); - ImpCastExprToType(LHS, RHSTy); // promote the integer to a pointer. + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_IntegralToPointer); return RHSTy; } if (LHSTy->isPointerType() && RHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); - ImpCastExprToType(RHS, LHSTy); // promote the integer to a pointer. + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_IntegralToPointer); return LHSTy; } @@ -3728,16 +3748,16 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { // Check if the pointee types are compatible ignoring the sign. // We explicitly check for char so that we catch "char" vs // "unsigned char" on systems where "char" is unsigned. - if (lhptee->isCharType()) { + if (lhptee->isCharType()) lhptee = Context.UnsignedCharTy; - } else if (lhptee->isSignedIntegerType()) { + else if (lhptee->isSignedIntegerType()) lhptee = Context.getCorrespondingUnsignedType(lhptee); - } - if (rhptee->isCharType()) { + + if (rhptee->isCharType()) rhptee = Context.UnsignedCharTy; - } else if (rhptee->isSignedIntegerType()) { + else if (rhptee->isSignedIntegerType()) rhptee = Context.getCorrespondingUnsignedType(rhptee); - } + if (lhptee == rhptee) { // Types are compatible ignoring the sign. Qualifier incompatibility // takes priority over sign incompatibility because the sign @@ -4003,14 +4023,14 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { // 2) null pointer constant if (FromType->isPointerType()) if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) { - ImpCastExprToType(rExpr, it->getType()); + ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_BitCast); InitField = *it; break; } if (rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, it->getType()); + ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_IntegralToPointer); InitField = *it; break; } @@ -4054,7 +4074,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { lhsType->isBlockPointerType()) && rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, lhsType); + ImpCastExprToType(rExpr, lhsType, CastExpr::CK_Unknown); return Compatible; } @@ -4077,7 +4097,8 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // The getNonReferenceType() call makes sure that the resulting expression // does not have reference type. if (result != Incompatible && rExpr->getType() != lhsType) - ImpCastExprToType(rExpr, lhsType.getNonReferenceType()); + ImpCastExprToType(rExpr, lhsType.getNonReferenceType(), + CastExpr::CK_Unknown); return result; } @@ -4128,7 +4149,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, QualType EltTy = LV->getElementType(); if (EltTy->isIntegralType() && rhsType->isIntegralType()) { if (Context.getIntegerTypeOrder(EltTy, rhsType) >= 0) { - ImpCastExprToType(rex, lhsType); + ImpCastExprToType(rex, lhsType, CastExpr::CK_IntegralCast); if (swapped) std::swap(rex, lex); return lhsType; } @@ -4136,7 +4157,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, if (EltTy->isRealFloatingType() && rhsType->isScalarType() && rhsType->isRealFloatingType()) { if (Context.getFloatingTypeOrder(EltTy, rhsType) >= 0) { - ImpCastExprToType(rex, lhsType); + ImpCastExprToType(rex, lhsType, CastExpr::CK_FloatingCast); if (swapped) std::swap(rex, lex); return lhsType; } @@ -4416,7 +4437,7 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, LHSTy = Context.getPromotedIntegerType(LHSTy); } if (!isCompAssign) - ImpCastExprToType(lex, LHSTy); + ImpCastExprToType(lex, LHSTy, CastExpr::CK_IntegralCast); UsualUnaryConversions(rex); @@ -4567,8 +4588,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return QualType(); } - ImpCastExprToType(lex, T); - ImpCastExprToType(rex, T); + ImpCastExprToType(lex, T, CastExpr::CK_BitCast); + ImpCastExprToType(rex, T, CastExpr::CK_BitCast); return ResultTy; } // C99 6.5.9p2 and C99 6.5.8p2 @@ -4593,7 +4614,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } if (LCanPointeeTy != RCanPointeeTy) - ImpCastExprToType(rex, lType); // promote the pointer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } @@ -4633,8 +4654,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return QualType(); } - ImpCastExprToType(lex, T); - ImpCastExprToType(rex, T); + ImpCastExprToType(lex, T, CastExpr::CK_BitCast); + ImpCastExprToType(rex, T, CastExpr::CK_BitCast); return ResultTy; } @@ -4653,7 +4674,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType); // promote the pointer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } // Allow block pointers to be compared with null pointer constants. @@ -4668,7 +4689,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType); // promote the pointer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } @@ -4686,14 +4707,14 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType); + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) { if (!Context.areComparableObjCPointerTypes(lType, rType)) Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - ImpCastExprToType(rex, lType); + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } } @@ -4711,7 +4732,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, DiagID) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType); // promote the integer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_IntegralToPointer); return ResultTy; } if (lType->isIntegerType() && rType->isAnyPointerType()) { @@ -4728,18 +4749,18 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, DiagID) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(lex, rType); // promote the integer to pointer + ImpCastExprToType(lex, rType, CastExpr::CK_IntegralToPointer); return ResultTy; } // Handle block pointers. if (!isRelational && RHSIsNull && lType->isBlockPointerType() && rType->isIntegerType()) { - ImpCastExprToType(rex, lType); // promote the integer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_IntegralToPointer); return ResultTy; } if (!isRelational && LHSIsNull && lType->isIntegerType() && rType->isBlockPointerType()) { - ImpCastExprToType(lex, rType); // promote the integer to pointer + ImpCastExprToType(lex, rType, CastExpr::CK_IntegralToPointer); return ResultTy; } return InvalidOperands(Loc, lex, rex); @@ -4812,9 +4833,16 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] UsualUnaryConversions(lex); UsualUnaryConversions(rex); - if (lex->getType()->isScalarType() && rex->getType()->isScalarType()) - return Context.IntTy; - return InvalidOperands(Loc, lex, rex); + if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType()) + return InvalidOperands(Loc, lex, rex); + + if (Context.getLangOptions().CPlusPlus) { + // C++ [expr.log.and]p2 + // C++ [expr.log.or]p2 + return Context.BoolTy; + } + + return Context.IntTy; } /// IsReadonlyProperty - Verify that otherwise a valid l-value expression diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 5f111c8a60e7..d4d031f91ed5 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -411,13 +411,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - ImpCastExprToType(ArraySize, Context.getSizeType()); + ImpCastExprToType(ArraySize, Context.getSizeType(), + CastExpr::CK_IntegralCast); } FunctionDecl *OperatorNew = 0; FunctionDecl *OperatorDelete = 0; Expr **PlaceArgs = (Expr**)PlacementArgs.get(); unsigned NumPlaceArgs = PlacementArgs.size(); + if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && FindAllocationFunctions(StartLoc, @@ -448,7 +450,9 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, Expr **ConsArgs = (Expr**)ConstructorArgs.get(); const RecordType *RT; unsigned NumConsArgs = ConstructorArgs.size(); - if (AllocType->isDependentType()) { + + if (AllocType->isDependentType() || + Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) { // Skip all the checks. } else if ((RT = AllocType->getAs<RecordType>()) && !AllocType->isAggregateType()) { @@ -491,7 +495,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) - + PlacementArgs.release(); ConstructorArgs.release(); ArraySizeE.release(); @@ -1043,6 +1047,40 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return PerformImplicitConversion(From, ToType, ICS, Flavor); } +/// BuildCXXDerivedToBaseExpr - This routine generates the suitable AST +/// for the derived to base conversion of the expression 'From'. All +/// necessary information is passed in ICS. +bool +Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, + const ImplicitConversionSequence& ICS, + const char *Flavor) { + QualType BaseType = + QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr); + // Must do additional defined to base conversion. + QualType DerivedType = + QualType::getFromOpaquePtr(ICS.UserDefined.After.FromTypePtr); + + From = new (Context) ImplicitCastExpr( + DerivedType.getNonReferenceType(), + CastKind, + From, + DerivedType->isLValueReferenceType()); + From = new (Context) ImplicitCastExpr(BaseType.getNonReferenceType(), + CastExpr::CK_DerivedToBase, From, + BaseType->isLValueReferenceType()); + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + OwningExprResult FromResult = + BuildCXXConstructExpr( + ICS.UserDefined.After.CopyConstructor->getLocation(), + BaseType, + ICS.UserDefined.After.CopyConstructor, + MultiExprArg(*this, (void **)&From, 1)); + if (FromResult.isInvalid()) + return true; + From = FromResult.takeAs<Expr>(); + return false; +} + /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit /// conversion sequence ICS. Returns true if there was an error, false @@ -1095,13 +1133,19 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (CastArg.isInvalid()) return true; + + if (ICS.UserDefined.After.Second == ICK_Derived_To_Base && + ICS.UserDefined.After.CopyConstructor) { + From = CastArg.takeAs<Expr>(); + return BuildCXXDerivedToBaseExpr(From, CastKind, ICS, Flavor); + } From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), - CastKind, CastArg.takeAs<Expr>(), + CastKind, CastArg.takeAs<Expr>(), ToType->isLValueReferenceType()); return false; - } - + } + case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); return false; @@ -1182,8 +1226,14 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) return true; - FixOverloadedFunctionReference(From, Fn); + From = FixOverloadedFunctionReference(From, Fn); FromType = From->getType(); + + // If there's already an address-of operator in the expression, we have + // the right type already, and the code below would just introduce an + // invalid additional pointer level. + if (FromType->isPointerType() || FromType->isMemberFunctionPointerType()) + break; } FromType = Context.getPointerType(FromType); ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay); @@ -1205,17 +1255,33 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; case ICK_Integral_Promotion: - case ICK_Floating_Promotion: - case ICK_Complex_Promotion: case ICK_Integral_Conversion: + ImpCastExprToType(From, ToType, CastExpr::CK_IntegralCast); + break; + + case ICK_Floating_Promotion: case ICK_Floating_Conversion: + ImpCastExprToType(From, ToType, CastExpr::CK_FloatingCast); + break; + + case ICK_Complex_Promotion: case ICK_Complex_Conversion: + ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); + break; + case ICK_Floating_Integral: + if (ToType->isFloatingType()) + ImpCastExprToType(From, ToType, CastExpr::CK_IntegralToFloating); + else + ImpCastExprToType(From, ToType, CastExpr::CK_FloatingToIntegral); + break; + case ICK_Complex_Real: + ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); + break; + case ICK_Compatible_Conversion: - // FIXME: Go deeper to get the unqualified type! - FromType = ToType.getUnqualifiedType(); - ImpCastExprToType(From, FromType); + ImpCastExprToType(From, ToType, CastExpr::CK_NoOp); break; case ICK_Pointer_Conversion: { @@ -1245,8 +1311,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; } case ICK_Boolean_Conversion: - FromType = Context.BoolTy; - ImpCastExprToType(From, FromType); + ImpCastExprToType(From, Context.BoolTy, CastExpr::CK_Unknown); break; default: @@ -1263,7 +1328,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue // references. ImpCastExprToType(From, ToType.getNonReferenceType(), - CastExpr::CK_Unknown, + CastExpr::CK_NoOp, ToType->isLValueReferenceType()); break; @@ -1465,7 +1530,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, SourceLocation Loc) { Expr *Args[2] = { LHS, RHS }; OverloadCandidateSet CandidateSet; - Self.AddBuiltinOperatorCandidates(OO_Conditional, Args, 2, CandidateSet); + Self.AddBuiltinOperatorCandidates(OO_Conditional, Loc, Args, 2, CandidateSet); OverloadCandidateSet::iterator Best; switch (Self.BestViableFunction(CandidateSet, Loc, Best)) { @@ -1691,12 +1756,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>(); if (LMemPtr && RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(RHS, LTy); + ImpCastExprToType(RHS, LTy, CastExpr::CK_NullToMemberPointer); return LTy; } if (RMemPtr && LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(LHS, RTy); + ImpCastExprToType(LHS, RTy, CastExpr::CK_NullToMemberPointer); return RTy; } if (LMemPtr && RMemPtr) { @@ -1787,11 +1852,17 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { // one operand is a null pointer constant, the composite pointer type is // the type of the other operand. if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(E1, T2); + if (T2->isMemberPointerType()) + ImpCastExprToType(E1, T2, CastExpr::CK_NullToMemberPointer); + else + ImpCastExprToType(E1, T2, CastExpr::CK_IntegralToPointer); return T2; } if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(E2, T1); + if (T1->isMemberPointerType()) + ImpCastExprToType(E2, T1, CastExpr::CK_NullToMemberPointer); + else + ImpCastExprToType(E2, T1, CastExpr::CK_IntegralToPointer); return T1; } @@ -2051,6 +2122,8 @@ Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, ClassName); else { TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS); + + // FIXME: If Base is dependent, we might not be able to resolve it here. if (!BaseTy) { Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) << ClassName; @@ -2060,25 +2133,41 @@ Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, BaseType = GetTypeFromParser(BaseTy); } - CanQualType CanBaseType = Context.getCanonicalType(BaseType); - DeclarationName DtorName = - Context.DeclarationNames.getCXXDestructorName(CanBaseType); + return ActOnDestructorReferenceExpr(S, move(Base), OpLoc, OpKind, + SourceRange(ClassNameLoc), + BaseType.getAsOpaquePtr(), + SS, HasTrailingLParen); +} +Sema::OwningExprResult +Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceRange TypeRange, + TypeTy *T, + const CXXScopeSpec &SS, + bool HasTrailingLParen) { + QualType Type = QualType::getFromOpaquePtr(T); + CanQualType CanType = Context.getCanonicalType(Type); + DeclarationName DtorName = + Context.DeclarationNames.getCXXDestructorName(CanType); + OwningExprResult Result - = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, - DtorName, DeclPtrTy(), &SS); + = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, + TypeRange.getBegin(), DtorName, DeclPtrTy(), + &SS); if (Result.isInvalid() || HasTrailingLParen) return move(Result); - + // The only way a reference to a destructor can be used is to // immediately call them. Since the next token is not a '(', produce a // diagnostic and build the call now. Expr *E = (Expr *)Result.get(); - SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(E->getLocEnd()); + SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(TypeRange.getEnd()); Diag(E->getLocStart(), diag::err_dtor_expr_without_call) << isa<CXXPseudoDestructorExpr>(E) << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); - + return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); } @@ -2154,9 +2243,14 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, MultiExprArg(*this, (void **)&From, 1), CastLoc, ConstructorArgs)) return ExprError(); - - return BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), - move_arg(ConstructorArgs)); + + OwningExprResult Result = + BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + move_arg(ConstructorArgs)); + if (Result.isInvalid()) + return ExprError(); + + return MaybeBindToTemporary(Result.takeAs<Expr>()); } case CastExpr::CK_UserDefinedConversion: { @@ -2168,7 +2262,7 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, // Create an implicit call expr that calls it. CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method); - return Owned(CE); + return MaybeBindToTemporary(CE); } } } @@ -2182,3 +2276,84 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { return Owned(FullExpr); } + +/// \brief Determine whether a reference to the given declaration in the +/// current context is an implicit member access +/// (C++ [class.mfct.non-static]p2). +/// +/// FIXME: Should Objective-C also use this approach? +/// +/// \param SS if non-NULL, the C++ nested-name-specifier that precedes the +/// name of the declaration referenced. +/// +/// \param D the declaration being referenced from the current scope. +/// +/// \param NameLoc the location of the name in the source. +/// +/// \param ThisType if the reference to this declaration is an implicit member +/// access, will be set to the type of the "this" pointer to be used when +/// building that implicit member access. +/// +/// \param MemberType if the reference to this declaration is an implicit +/// member access, will be set to the type of the member being referenced +/// (for use at the type of the resulting member access expression). +/// +/// \returns true if this is an implicit member reference (in which case +/// \p ThisType and \p MemberType will be set), or false if it is not an +/// implicit member reference. +bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, + SourceLocation NameLoc, QualType &ThisType, + QualType &MemberType) { + // If this isn't a C++ method, then it isn't an implicit member reference. + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext); + if (!MD || MD->isStatic()) + return false; + + // C++ [class.mfct.nonstatic]p2: + // [...] if name lookup (3.4.1) resolves the name in the + // id-expression to a nonstatic nontype member of class X or of + // a base class of X, the id-expression is transformed into a + // class member access expression (5.2.5) using (*this) (9.3.2) + // as the postfix-expression to the left of the '.' operator. + DeclContext *Ctx = 0; + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + Ctx = FD->getDeclContext(); + MemberType = FD->getType(); + + if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>()) + MemberType = RefType->getPointeeType(); + else if (!FD->isMutable()) + MemberType + = Context.getQualifiedType(MemberType, + Qualifiers::fromCVRMask(MD->getTypeQualifiers())); + } else { + for (OverloadIterator Ovl(D), OvlEnd; Ovl != OvlEnd; ++Ovl) { + CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl); + FunctionTemplateDecl *FunTmpl = 0; + if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl))) + Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + + if (Method && !Method->isStatic()) { + Ctx = Method->getParent(); + if (isa<CXXMethodDecl>(D) && !FunTmpl) + MemberType = Method->getType(); + else + MemberType = Context.OverloadTy; + break; + } + } + } + + if (!Ctx || !Ctx->isRecord()) + return false; + + // Determine whether the declaration(s) we found are actually in a base + // class. If not, this isn't an implicit member reference. + ThisType = MD->getThisType(Context); + QualType CtxType = Context.getTypeDeclType(cast<CXXRecordDecl>(Ctx)); + QualType ClassType + = Context.getTypeDeclType(cast<CXXRecordDecl>(MD->getParent())); + return Context.hasSameType(CtxType, ClassType) || + IsDerivedFrom(ClassType, CtxType); +} + diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index d7e4e4a67fe9..b78c10b0dd80 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -636,7 +636,11 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, // Implicitly convert integers and pointers to 'id' but emit a warning. Diag(lbrac, diag::warn_bad_receiver_type) << RExpr->getType() << RExpr->getSourceRange(); - ImpCastExprToType(RExpr, Context.getObjCIdType()); + if (ReceiverCType->isPointerType()) + ImpCastExprToType(RExpr, Context.getObjCIdType(), CastExpr::CK_BitCast); + else + ImpCastExprToType(RExpr, Context.getObjCIdType(), + CastExpr::CK_IntegralToPointer); } else { // Reject other random receiver types (e.g. structs). Diag(lbrac, diag::err_bad_receiver_type) diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 27f089680763..4746a2597e55 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -109,9 +109,9 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { llvm::APSInt ConstVal(32); ConstVal = StrLength; // Return a new array type (C99 6.7.8p22). - DeclT = S.Context.getConstantArrayWithoutExprType(IAT->getElementType(), - ConstVal, - ArrayType::Normal, 0); + DeclT = S.Context.getConstantArrayType(IAT->getElementType(), + ConstVal, + ArrayType::Normal, 0); return; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 99e7b0811c91..ebcf3ad8e2bc 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1934,14 +1934,43 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, return ImplicitConversionSequence::Worse; } } - - - // FIXME: conversion of A::* to B::* is better than conversion of - // A::* to C::*, - - // FIXME: conversion of B::* to C::* is better than conversion of - // A::* to C::*, and - + + // Ranking of member-pointer types. + if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member && + FromType1->isMemberPointerType() && FromType2->isMemberPointerType() && + ToType1->isMemberPointerType() && ToType2->isMemberPointerType()) { + const MemberPointerType * FromMemPointer1 = + FromType1->getAs<MemberPointerType>(); + const MemberPointerType * ToMemPointer1 = + ToType1->getAs<MemberPointerType>(); + const MemberPointerType * FromMemPointer2 = + FromType2->getAs<MemberPointerType>(); + const MemberPointerType * ToMemPointer2 = + ToType2->getAs<MemberPointerType>(); + const Type *FromPointeeType1 = FromMemPointer1->getClass(); + const Type *ToPointeeType1 = ToMemPointer1->getClass(); + const Type *FromPointeeType2 = FromMemPointer2->getClass(); + const Type *ToPointeeType2 = ToMemPointer2->getClass(); + QualType FromPointee1 = QualType(FromPointeeType1, 0).getUnqualifiedType(); + QualType ToPointee1 = QualType(ToPointeeType1, 0).getUnqualifiedType(); + QualType FromPointee2 = QualType(FromPointeeType2, 0).getUnqualifiedType(); + QualType ToPointee2 = QualType(ToPointeeType2, 0).getUnqualifiedType(); + // conversion of A::* to B::* is better than conversion of A::* to C::*, + if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { + if (IsDerivedFrom(ToPointee1, ToPointee2)) + return ImplicitConversionSequence::Worse; + else if (IsDerivedFrom(ToPointee2, ToPointee1)) + return ImplicitConversionSequence::Better; + } + // conversion of B::* to C::* is better than conversion of A::* to C::* + if (ToPointee1 == ToPointee2 && FromPointee1 != FromPointee2) { + if (IsDerivedFrom(FromPointee1, FromPointee2)) + return ImplicitConversionSequence::Better; + else if (IsDerivedFrom(FromPointee2, FromPointee1)) + return ImplicitConversionSequence::Worse; + } + } + if (SCS1.CopyConstructor && SCS2.CopyConstructor && SCS1.Second == ICK_Derived_To_Base) { // -- conversion of C to B is better than conversion of C to A, @@ -2539,6 +2568,18 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.Viable = false; return; } + + // We won't go through a user-define type conversion function to convert a + // derived to base as such conversions are given Conversion Rank. They only + // go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user] + QualType FromCanon + = Context.getCanonicalType(From->getType().getUnqualifiedType()); + QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); + if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { + Candidate.Viable = false; + return; + } + // To determine what the conversion from the result of calling the // conversion function to the type we're eventually trying to @@ -2551,7 +2592,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, DeclRefExpr ConversionRef(Conversion, Conversion->getType(), SourceLocation()); ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()), - CastExpr::CK_Unknown, + CastExpr::CK_FunctionToPointerDecay, &ConversionRef, false); // Note that it is safe to allocate CallExpr on the stack here because @@ -2723,7 +2764,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, ArgumentDependentLookup(OpName, Args, NumArgs, Functions); AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet); AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange); - AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet); } /// \brief Add overload candidates for overloaded operators that are @@ -2873,7 +2914,8 @@ class BuiltinCandidateTypeSet { /// Context - The AST context in which we will build the type sets. ASTContext &Context; - bool AddPointerWithMoreQualifiedTypeVariants(QualType Ty); + bool AddPointerWithMoreQualifiedTypeVariants(QualType Ty, + const Qualifiers &VisibleQuals); bool AddMemberPointerWithMoreQualifiedTypeVariants(QualType Ty); public: @@ -2883,8 +2925,11 @@ public: BuiltinCandidateTypeSet(Sema &SemaRef) : SemaRef(SemaRef), Context(SemaRef.Context) { } - void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions, - bool AllowExplicitConversions); + void AddTypesConvertedFrom(QualType Ty, + SourceLocation Loc, + bool AllowUserConversions, + bool AllowExplicitConversions, + const Qualifiers &VisibleTypeConversionsQuals); /// pointer_begin - First pointer type found; iterator pointer_begin() { return PointerTypes.begin(); } @@ -2915,7 +2960,8 @@ public: /// /// FIXME: what to do about extended qualifiers? bool -BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) { +BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, + const Qualifiers &VisibleQuals) { // Insert this type. if (!PointerTypes.insert(Ty)) @@ -2926,11 +2972,16 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) { QualType PointeeTy = PointerTy->getPointeeType(); unsigned BaseCVR = PointeeTy.getCVRQualifiers(); - + bool hasVolatile = VisibleQuals.hasVolatile(); + bool hasRestrict = VisibleQuals.hasRestrict(); + // Iterate through all strict supersets of BaseCVR. for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { if ((CVR | BaseCVR) != CVR) continue; - + // Skip over Volatile/Restrict if no Volatile/Restrict found anywhere + // in the types. + if ((CVR & Qualifiers::Volatile) && !hasVolatile) continue; + if ((CVR & Qualifiers::Restrict) && !hasRestrict) continue; QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR); PointerTypes.insert(Context.getPointerType(QPointeeTy)); } @@ -2983,8 +3034,10 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( /// type. void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, + SourceLocation Loc, bool AllowUserConversions, - bool AllowExplicitConversions) { + bool AllowExplicitConversions, + const Qualifiers &VisibleQuals) { // Only deal with canonical types. Ty = Context.getCanonicalType(Ty); @@ -3001,33 +3054,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // Insert our type, and its more-qualified variants, into the set // of types. - if (!AddPointerWithMoreQualifiedTypeVariants(Ty)) + if (!AddPointerWithMoreQualifiedTypeVariants(Ty, VisibleQuals)) return; - - // Add 'cv void*' to our set of types. - if (!Ty->isVoidType()) { - QualType QualVoid - = Context.getCVRQualifiedType(Context.VoidTy, - PointeeTy.getCVRQualifiers()); - AddPointerWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid)); - } - - // If this is a pointer to a class type, add pointers to its bases - // (with the same level of cv-qualification as the original - // derived class, of course). - if (const RecordType *PointeeRec = PointeeTy->getAs<RecordType>()) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(PointeeRec->getDecl()); - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - QualType BaseTy = Context.getCanonicalType(Base->getType()); - BaseTy = Context.getCVRQualifiedType(BaseTy.getUnqualifiedType(), - PointeeTy.getCVRQualifiers()); - - // Add the pointer type, recursively, so that we get all of - // the indirect base classes, too. - AddTypesConvertedFrom(Context.getPointerType(BaseTy), false, false); - } - } } else if (Ty->isMemberPointerType()) { // Member pointers are far easier, since the pointee can't be converted. if (!AddMemberPointerWithMoreQualifiedTypeVariants(Ty)) @@ -3036,7 +3064,7 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, EnumerationTypes.insert(Ty); } else if (AllowUserConversions) { if (const RecordType *TyRec = Ty->getAs<RecordType>()) { - if (SemaRef.RequireCompleteType(SourceLocation(), Ty, 0)) { + if (SemaRef.RequireCompleteType(Loc, Ty, 0)) { // No conversion functions in incomplete types. return; } @@ -3056,8 +3084,10 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, if (ConvTemplate) continue; - if (AllowExplicitConversions || !Conv->isExplicit()) - AddTypesConvertedFrom(Conv->getConversionType(), false, false); + if (AllowExplicitConversions || !Conv->isExplicit()) { + AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, + VisibleQuals); + } } } } @@ -3089,6 +3119,58 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S, } } +/// CollectVRQualifiers - This routine returns Volatile/Restrict qualifiers +/// , if any, found in visible type conversion functions found in ArgExpr's +/// type. +static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { + Qualifiers VRQuals; + const RecordType *TyRec; + if (const MemberPointerType *RHSMPType = + ArgExpr->getType()->getAs<MemberPointerType>()) + TyRec = cast<RecordType>(RHSMPType->getClass()); + else + TyRec = ArgExpr->getType()->getAs<RecordType>(); + if (!TyRec) { + // Just to be safe, assume the worst case. + VRQuals.addVolatile(); + VRQuals.addRestrict(); + return VRQuals; + } + + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); + OverloadedFunctionDecl *Conversions = + ClassDecl->getVisibleConversionFunctions(); + + for (OverloadedFunctionDecl::function_iterator Func + = Conversions->function_begin(); + Func != Conversions->function_end(); ++Func) { + if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*Func)) { + QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); + if (const ReferenceType *ResTypeRef = CanTy->getAs<ReferenceType>()) + CanTy = ResTypeRef->getPointeeType(); + // Need to go down the pointer/mempointer chain and add qualifiers + // as see them. + bool done = false; + while (!done) { + if (const PointerType *ResTypePtr = CanTy->getAs<PointerType>()) + CanTy = ResTypePtr->getPointeeType(); + else if (const MemberPointerType *ResTypeMPtr = + CanTy->getAs<MemberPointerType>()) + CanTy = ResTypeMPtr->getPointeeType(); + else + done = true; + if (CanTy.isVolatileQualified()) + VRQuals.addVolatile(); + if (CanTy.isRestrictQualified()) + VRQuals.addRestrict(); + if (VRQuals.hasRestrict() && VRQuals.hasVolatile()) + return VRQuals; + } + } + } + return VRQuals; +} + /// AddBuiltinOperatorCandidates - Add the appropriate built-in /// operator overloads to the candidate set (C++ [over.built]), based /// on the operator @p Op and the arguments given. For example, if the @@ -3096,6 +3178,7 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S, /// operator+(int, int)" to cover integer addition. void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet) { // The set of "promoted arithmetic types", which are the arithmetic @@ -3119,10 +3202,25 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy, Context.FloatTy, Context.DoubleTy, Context.LongDoubleTy }; - + assert(ArithmeticTypes[FirstPromotedIntegralType] == Context.IntTy && + "Invalid first promoted integral type"); + assert(ArithmeticTypes[LastPromotedIntegralType - 1] + == Context.UnsignedLongLongTy && + "Invalid last promoted integral type"); + assert(ArithmeticTypes[FirstPromotedArithmeticType] == Context.IntTy && + "Invalid first promoted arithmetic type"); + assert(ArithmeticTypes[LastPromotedArithmeticType - 1] + == Context.LongDoubleTy && + "Invalid last promoted arithmetic type"); + // Find all of the types that the arguments can convert to, but only // if the operator we're looking at has built-in operator candidates // that make use of these types. + Qualifiers VisibleTypeConversionsQuals; + VisibleTypeConversionsQuals.addConst(); + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); + BuiltinCandidateTypeSet CandidateTypes(*this); if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual || Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual || @@ -3132,10 +3230,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, (Op == OO_Star && NumArgs == 1) || Op == OO_Conditional) { for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(), + OpLoc, true, (Op == OO_Exclaim || Op == OO_AmpAmp || - Op == OO_PipePipe)); + Op == OO_PipePipe), + VisibleTypeConversionsQuals); } bool isComparison = false; @@ -3202,14 +3302,17 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); else AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); - - // Volatile version - ParamTypes[0] - = Context.getLValueReferenceType(Context.getVolatileType(ArithTy)); - if (NumArgs == 1) - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); - else - AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); + // heuristic to reduce number of builtin candidates in the set. + // Add volatile version only if there are conversions to a volatile type. + if (VisibleTypeConversionsQuals.hasVolatile()) { + // Volatile version + ParamTypes[0] + = Context.getLValueReferenceType(Context.getVolatileType(ArithTy)); + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); + } } // C++ [over.built]p5: @@ -3238,7 +3341,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, else AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); - if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { + if (!Context.getCanonicalType(*Ptr).isVolatileQualified() && + VisibleTypeConversionsQuals.hasVolatile()) { // With volatile ParamTypes[0] = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); @@ -3550,7 +3654,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, /*IsAssigmentOperator=*/Op == OO_Equal); - if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { + if (!Context.getCanonicalType(*Ptr).isVolatileQualified() && + VisibleTypeConversionsQuals.hasVolatile()) { // volatile version ParamTypes[0] = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); @@ -3586,10 +3691,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, /*IsAssigmentOperator=*/Op == OO_Equal); // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = Context.getVolatileType(ArithmeticTypes[Left]); - ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssigmentOperator=*/Op == OO_Equal); + if (VisibleTypeConversionsQuals.hasVolatile()) { + ParamTypes[0] = Context.getVolatileType(ArithmeticTypes[Left]); + ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + } } } break; @@ -3621,12 +3728,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); - - // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = ArithmeticTypes[Left]; - ParamTypes[0] = Context.getVolatileType(ParamTypes[0]); - ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + if (VisibleTypeConversionsQuals.hasVolatile()) { + // Add this built-in operator as a candidate (VQ is 'volatile'). + ParamTypes[0] = ArithmeticTypes[Left]; + ParamTypes[0] = Context.getVolatileType(ParamTypes[0]); + ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + } } } break; @@ -3708,6 +3816,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, C1 = QualType(Q1.strip(PointerTy->getPointeeType()), 0); if (!isa<RecordType>(C1)) continue; + // heuristic to reduce number of builtin candidates in the set. + // Add volatile/restrict version only if there are conversions to a + // volatile/restrict type. + if (!VisibleTypeConversionsQuals.hasVolatile() && Q1.hasVolatile()) + continue; + if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict()) + continue; } for (BuiltinCandidateTypeSet::iterator MemPtr = CandidateTypes.member_pointer_begin(), @@ -3721,6 +3836,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, QualType ParamTypes[2] = { *Ptr, *MemPtr }; // build CV12 T& QualType T = mptr->getPointeeType(); + if (!VisibleTypeConversionsQuals.hasVolatile() && + T.isVolatileQualified()) + continue; + if (!VisibleTypeConversionsQuals.hasRestrict() && + T.isRestrictQualified()) + continue; T = Q1.apply(T); QualType ResultTy = Context.getLValueReferenceType(T); AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); @@ -4061,13 +4182,20 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, } else if (OnlyViable) { assert(Cand->Conversions.size() <= 2 && "builtin-binary-operator-not-binary"); - if (Cand->Conversions.size() == 1) - Diag(OpLoc, diag::err_ovl_builtin_unary_candidate) - << Opc << Cand->BuiltinTypes.ParamTypes[0]; - else - Diag(OpLoc, diag::err_ovl_builtin_binary_candidate) - << Opc << Cand->BuiltinTypes.ParamTypes[0] - << Cand->BuiltinTypes.ParamTypes[1]; + std::string TypeStr("operator"); + TypeStr += Opc; + TypeStr += "("; + TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString(); + if (Cand->Conversions.size() == 1) { + TypeStr += ")"; + Diag(OpLoc, diag::err_ovl_builtin_unary_candidate) << TypeStr; + } + else { + TypeStr += ", "; + TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString(); + TypeStr += ")"; + Diag(OpLoc, diag::err_ovl_builtin_binary_candidate) << TypeStr; + } } else if (!Cand->Viable && !Reported) { // Non-viability might be due to ambiguous user-defined conversions, @@ -4150,6 +4278,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, OvlExpr = UnOp->getSubExpr()->IgnoreParens(); } + bool HasExplicitTemplateArgs = false; + const TemplateArgument *ExplicitTemplateArgs = 0; + unsigned NumExplicitTemplateArgs = 0; + // Try to dig out the overloaded function. FunctionTemplateDecl *FunctionTemplate = 0; if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) { @@ -4159,9 +4291,17 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, Ovl = dyn_cast<OverloadedFunctionDecl>(ME->getMemberDecl()); FunctionTemplate = dyn_cast<FunctionTemplateDecl>(ME->getMemberDecl()); // FIXME: Explicit template arguments + } else if (TemplateIdRefExpr *TIRE = dyn_cast<TemplateIdRefExpr>(OvlExpr)) { + TemplateName Name = TIRE->getTemplateName(); + Ovl = Name.getAsOverloadedFunctionDecl(); + FunctionTemplate = + dyn_cast_or_null<FunctionTemplateDecl>(Name.getAsTemplateDecl()); + + HasExplicitTemplateArgs = true; + ExplicitTemplateArgs = TIRE->getTemplateArgs(); + NumExplicitTemplateArgs = TIRE->getNumTemplateArgs(); } - // FIXME: TemplateIdRefExpr? - + // If there's no overloaded function declaration or function template, // we're done. if (!Ovl && !FunctionTemplate) @@ -4206,8 +4346,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, FunctionDecl *Specialization = 0; TemplateDeductionInfo Info(Context); if (TemplateDeductionResult Result - = DeduceTemplateArguments(FunctionTemplate, /*FIXME*/false, - /*FIXME:*/0, /*FIXME:*/0, + = DeduceTemplateArguments(FunctionTemplate, HasExplicitTemplateArgs, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, FunctionType, Specialization, Info)) { // FIXME: make a note of the failed deduction for diagnostics. (void)Result; @@ -4240,8 +4381,11 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // If there were 0 or 1 matches, we're done. if (Matches.empty()) return 0; - else if (Matches.size() == 1) - return *Matches.begin(); + else if (Matches.size() == 1) { + FunctionDecl *Result = *Matches.begin(); + MarkDeclarationReferenced(From->getLocStart(), Result); + return Result; + } // C++ [over.over]p4: // If more than one function is selected, [...] @@ -4257,14 +4401,17 @@ 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(), + llvm::SmallVector<FunctionDecl *, 8> TemplateMatches(Matches.begin(), Matches.end()); - return getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(), - TPOC_Other, From->getLocStart(), - PDiag(), - PDiag(diag::err_addr_ovl_ambiguous) - << TemplateMatches[0]->getDeclName(), - PDiag(diag::err_ovl_template_candidate)); + FunctionDecl *Result = + getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(), + TPOC_Other, From->getLocStart(), + PDiag(), + PDiag(diag::err_addr_ovl_ambiguous) + << TemplateMatches[0]->getDeclName(), + PDiag(diag::err_ovl_template_candidate)); + MarkDeclarationReferenced(From->getLocStart(), Result); + return Result; } // [...] any function template specializations in the set are @@ -4276,8 +4423,11 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // [...] After such eliminations, if any, there shall remain exactly one // selected function. - if (RemainingMatches.size() == 1) - return RemainingMatches.front(); + if (RemainingMatches.size() == 1) { + FunctionDecl *Result = RemainingMatches.front(); + MarkDeclarationReferenced(From->getLocStart(), Result); + return Result; + } // FIXME: We should probably return the same thing that BestViableFunction // returns (even if we issue the diagnostics here). @@ -4511,7 +4661,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(Op, &Args[0], NumArgs, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); // Perform overload resolution. OverloadCandidateSet::iterator Best; @@ -4671,7 +4821,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(Op, Args, 2, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); // Perform overload resolution. OverloadCandidateSet::iterator Best; @@ -4925,6 +5075,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); + if (RequireCompleteType(LParenLoc, Object->getType(), + PartialDiagnostic(diag::err_incomplete_object_call) + << Object->getSourceRange())) + return true; + // C++ [over.call.object]p2: // In addition, for each conversion function declared in T of the // form @@ -4942,33 +5097,30 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. + // FIXME: Look in base classes for more conversion operators! + OverloadedFunctionDecl *Conversions + = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + CXXConversionDecl *Conv; + FunctionTemplateDecl *ConvTemplate; + GetFunctionAndTemplate(*Func, Conv, ConvTemplate); - if (!RequireCompleteType(SourceLocation(), Object->getType(), 0)) { - // FIXME: Look in base classes for more conversion operators! - OverloadedFunctionDecl *Conversions - = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Func = Conversions->function_begin(), - FuncEnd = Conversions->function_end(); - Func != FuncEnd; ++Func) { - CXXConversionDecl *Conv; - FunctionTemplateDecl *ConvTemplate; - GetFunctionAndTemplate(*Func, Conv, ConvTemplate); - - // Skip over templated conversion functions; they aren't - // surrogates. - if (ConvTemplate) - continue; + // Skip over templated conversion functions; they aren't + // surrogates. + if (ConvTemplate) + continue; - // Strip the reference type (if any) and then the pointer type (if - // any) to get down to what might be a function type. - QualType ConvType = Conv->getConversionType().getNonReferenceType(); - if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) - ConvType = ConvPtrType->getPointeeType(); + // Strip the reference type (if any) and then the pointer type (if + // any) to get down to what might be a function type. + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + ConvType = ConvPtrType->getPointeeType(); - if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) - AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); - } + if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) + AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); } // Perform overload resolution. @@ -5205,11 +5357,12 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { /// a C++ overloaded function (possibly with some parentheses and /// perhaps a '&' around it). We have resolved the overloaded function /// to the function declaration Fn, so patch up the expression E to -/// refer (possibly indirectly) to Fn. -void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { +/// refer (possibly indirectly) to Fn. Returns the new expr. +Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { - FixOverloadedFunctionReference(PE->getSubExpr(), Fn); - E->setType(PE->getSubExpr()->getType()); + Expr *NewExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); + NewExpr->setType(PE->getSubExpr()->getType()); + return NewExpr; } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) { assert(UnOp->getOpcode() == UnaryOperator::AddrOf && "Can only take the address of an overloaded function"); @@ -5228,11 +5381,16 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); E->setType(Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr())); - return; + return E; } + // FIXME: TemplateIdRefExpr referring to a member function template + // specialization! } - FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); - E->setType(Context.getPointerType(UnOp->getSubExpr()->getType())); + Expr *NewExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + UnOp->setSubExpr(NewExpr); + UnOp->setType(Context.getPointerType(NewExpr->getType())); + + return UnOp; } else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { assert((isa<OverloadedFunctionDecl>(DR->getDecl()) || isa<FunctionTemplateDecl>(DR->getDecl())) && @@ -5242,9 +5400,24 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) { MemExpr->setMemberDecl(Fn); E->setType(Fn->getType()); + } else if (TemplateIdRefExpr *TID = dyn_cast<TemplateIdRefExpr>(E)) { + // FIXME: We should capture the template arguments here. + if (NestedNameSpecifier *Qualifier = TID->getQualifier()) + E = new (Context) QualifiedDeclRefExpr(Fn, Fn->getType(), + TID->getTemplateNameLoc(), + /*FIXME?*/false, /*FIXME?*/false, + TID->getQualifierRange(), + Qualifier); + else + E = new (Context) DeclRefExpr(Fn, Fn->getType(), + TID->getTemplateNameLoc()); + + TID->Destroy(Context); } else { assert(false && "Invalid reference to overloaded function"); } + + return E; } } // end namespace clang diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index e8cd6b081de1..145342438503 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -368,6 +368,21 @@ static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs, return false; } +/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of +/// potentially integral-promoted expression @p expr. +static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { + const ImplicitCastExpr *ImplicitCast = + dyn_cast_or_null<ImplicitCastExpr>(expr); + if (ImplicitCast != NULL) { + const Expr *ExprBeforePromotion = ImplicitCast->getSubExpr(); + QualType TypeBeforePromotion = ExprBeforePromotion->getType(); + if (TypeBeforePromotion->isIntegralType()) { + return TypeBeforePromotion; + } + } + return expr->getType(); +} + Action::OwningStmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body) { @@ -382,11 +397,30 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, Expr *CondExpr = SS->getCond(); QualType CondType = CondExpr->getType(); - if (!CondExpr->isTypeDependent() && - !CondType->isIntegerType()) { // C99 6.8.4.2p1 - Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) - << CondType << CondExpr->getSourceRange(); - return StmtError(); + // C++ 6.4.2.p2: + // Integral promotions are performed (on the switch condition). + // + // A case value unrepresentable by the original switch condition + // type (before the promotion) doesn't make sense, even when it can + // be represented by the promoted type. Therefore we need to find + // the pre-promotion type of the switch condition. + QualType CondTypeBeforePromotion = + GetTypeBeforeIntegralPromotion(CondExpr); + + if (!CondExpr->isTypeDependent()) { + if (!CondType->isIntegerType()) { // C99 6.8.4.2p1 + Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) + << CondType << CondExpr->getSourceRange(); + return StmtError(); + } + + if (CondTypeBeforePromotion->isBooleanType()) { + // switch(bool_expr) {...} is often a programmer error, e.g. + // switch(n && mask) { ... } // Doh - should be "n & mask". + // One can always use an if statement instead of switch(bool_expr). + Diag(SwitchLoc, diag::warn_bool_switch_condition) + << CondExpr->getSourceRange(); + } } // Get the bitwidth of the switched-on value before promotions. We must @@ -395,8 +429,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); unsigned CondWidth = HasDependentValue? 0 - : static_cast<unsigned>(Context.getTypeSize(CondType)); - bool CondIsSigned = CondType->isSignedIntegerType(); + : static_cast<unsigned>(Context.getTypeSize(CondTypeBeforePromotion)); + bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType(); // Accumulate all of the case values in a vector so that we can sort them // and detect duplicates. This vector contains the APInt for the case after @@ -448,7 +482,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Lo, CondType); + ImpCastExprToType(Lo, CondType, CastExpr::CK_IntegralCast); CS->setLHS(Lo); // If this is a case range, remember it in CaseRanges, otherwise CaseVals. @@ -504,7 +538,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Hi, CondType); + ImpCastExprToType(Hi, CondType, CastExpr::CK_IntegralCast); CR->setRHS(Hi); // If the low value is bigger than the high value, the case is empty. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ab0bbe081dbf..0f223208a938 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1251,7 +1251,9 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, return ElabType.getAsOpaquePtr(); } -Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template, +Sema::OwningExprResult Sema::BuildTemplateIdExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, @@ -1261,16 +1263,36 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template, // template arguments that we have against the template name, if the template // name refers to a single template. That's not a terribly common case, // though. - return Owned(TemplateIdRefExpr::Create(Context, - /*FIXME: New type?*/Context.OverloadTy, - /*FIXME: Necessary?*/0, - /*FIXME: Necessary?*/SourceRange(), + + // Cope with an implicit member access in a C++ non-static member function. + NamedDecl *D = Template.getAsTemplateDecl(); + if (!D) + D = Template.getAsOverloadedFunctionDecl(); + + CXXScopeSpec SS; + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + QualType ThisType, MemberType; + if (D && isImplicitMemberReference(&SS, D, TemplateNameLoc, + ThisType, MemberType)) { + Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); + return Owned(MemberExpr::Create(Context, This, true, + Qualifier, QualifierRange, + D, TemplateNameLoc, true, + LAngleLoc, TemplateArgs, + NumTemplateArgs, RAngleLoc, + Context.OverloadTy)); + } + + return Owned(TemplateIdRefExpr::Create(Context, Context.OverloadTy, + Qualifier, QualifierRange, Template, TemplateNameLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc)); } -Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD, +Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS, + TemplateTy TemplateD, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, @@ -1283,7 +1305,9 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD, translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); TemplateArgsIn.release(); - return BuildTemplateIdExpr(Template, TemplateNameLoc, LAngleLoc, + return BuildTemplateIdExpr((NestedNameSpecifier *)SS.getScopeRep(), + SS.getRange(), + Template, TemplateNameLoc, LAngleLoc, TemplateArgs.data(), TemplateArgs.size(), RAngleLoc); } @@ -1706,7 +1730,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, bool Invalid = false; // See through any implicit casts we added to fix the type. - if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) + while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) Arg = Cast->getSubExpr(); // C++0x allows nullptr, and there's no further checking to be done for that. @@ -1808,7 +1832,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { bool Invalid = false; // See through any implicit casts we added to fix the type. - if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) + while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) Arg = Cast->getSubExpr(); // C++0x allows nullptr, and there's no further checking to be done for that. @@ -1936,7 +1960,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } else if (IsIntegralPromotion(Arg, ArgType, ParamType) || !ParamType->isEnumeralType()) { // This is an integral promotion or conversion. - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_IntegralCast); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), @@ -2025,20 +2049,23 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() || ParamType->isMemberPointerType())) { ArgType = ParamType; - ImpCastExprToType(Arg, ParamType); + if (ParamType->isMemberPointerType()) + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer); + else + ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast); } else if (ArgType->isFunctionType() && ParamType->isPointerType()) { ArgType = Context.getPointerType(ArgType); - ImpCastExprToType(Arg, ArgType); + ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay); } else if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) return true; - FixOverloadedFunctionReference(Arg, Fn); + Arg = FixOverloadedFunctionReference(Arg, Fn); ArgType = Arg->getType(); if (ArgType->isFunctionType() && ParamType->isPointerType()) { ArgType = Context.getPointerType(Arg->getType()); - ImpCastExprToType(Arg, ArgType); + ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay); } } @@ -2083,15 +2110,15 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (ArgType->isNullPtrType()) { ArgType = ParamType; - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast); } else if (ArgType->isArrayType()) { ArgType = Context.getArrayDecayedType(ArgType); - ImpCastExprToType(Arg, ArgType); + ImpCastExprToType(Arg, ArgType, CastExpr::CK_ArrayToPointerDecay); } if (IsQualificationConversion(ArgType, ParamType)) { ArgType = ParamType; - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp); } if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) { @@ -2162,9 +2189,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Context.hasSameUnqualifiedType(ParamType, ArgType)) { // Types match exactly: nothing more to do here. } else if (ArgType->isNullPtrType()) { - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer); } else if (IsQualificationConversion(ArgType, ParamType)) { - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), @@ -3038,6 +3065,173 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, return DeclPtrTy(); } +/// \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 +/// new specialization/instantiation will have any effect. +/// +/// \param S the semantic analysis object. +/// +/// \param NewLoc the location of the new explicit specialization or +/// instantiation. +/// +/// \param NewTSK the kind of the new explicit specialization or instantiation. +/// +/// \param PrevDecl the previous declaration of the entity. +/// +/// \param PrevTSK the kind of the old explicit specialization or instantiatin. +/// +/// \param PrevPointOfInstantiation if valid, indicates where the previus +/// declaration was instantiated (either implicitly or explicitly). +/// +/// \param SuppressNew will be set to true to indicate that the new +/// specialization or instantiation has no effect and should be ignored. +/// +/// \returns true if there was an error that should prevent the introduction of +/// the new declaration into the AST, false otherwise. +static bool +CheckSpecializationInstantiationRedecl(Sema &S, + SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPointOfInstantiation, + bool &SuppressNew) { + SuppressNew = false; + + switch (NewTSK) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + assert(false && "Don't check implicit instantiations here"); + return false; + + case TSK_ExplicitSpecialization: + switch (PrevTSK) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + // Okay, we're just specializing something that is either already + // explicitly specialized or has merely been mentioned without any + // instantiation. + return false; + + case TSK_ImplicitInstantiation: + if (PrevPointOfInstantiation.isInvalid()) { + // The declaration itself has not actually been instantiated, so it is + // still okay to specialize it. + return false; + } + // Fall through + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + assert((PrevTSK == TSK_ImplicitInstantiation || + PrevPointOfInstantiation.isValid()) && + "Explicit instantiation without point of instantiation?"); + + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template + // is explicitly specialized then that specialization shall be declared + // before the first use of that specialization that would cause an + // implicit instantiation to take place, in every translation unit in + // which such a use occurs; no diagnostic is required. + S.Diag(NewLoc, diag::err_specialization_after_instantiation) + << PrevDecl; + S.Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) + << (PrevTSK != TSK_ImplicitInstantiation); + + return true; + } + break; + + case TSK_ExplicitInstantiationDeclaration: + switch (PrevTSK) { + case TSK_ExplicitInstantiationDeclaration: + // This explicit instantiation declaration is redundant (that's okay). + SuppressNew = true; + return false; + + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // We're explicitly instantiating something that may have already been + // implicitly instantiated; that's fine. + return false; + + case TSK_ExplicitSpecialization: + // C++0x [temp.explicit]p4: + // For a given set of template parameters, if an explicit instantiation + // of a template appears after a declaration of an explicit + // specialization for that template, the explicit instantiation has no + // effect. + return false; + + case TSK_ExplicitInstantiationDefinition: + // C++0x [temp.explicit]p10: + // If an entity is the subject of both an explicit instantiation + // declaration and an explicit instantiation definition in the same + // translation unit, the definition shall follow the declaration. + S.Diag(NewLoc, + diag::err_explicit_instantiation_declaration_after_definition); + S.Diag(PrevPointOfInstantiation, + diag::note_explicit_instantiation_definition_here); + assert(PrevPointOfInstantiation.isValid() && + "Explicit instantiation without point of instantiation?"); + SuppressNew = true; + return false; + } + break; + + case TSK_ExplicitInstantiationDefinition: + switch (PrevTSK) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // We're explicitly instantiating something that may have already been + // implicitly instantiated; that's fine. + return false; + + case TSK_ExplicitSpecialization: + // C++ DR 259, C++0x [temp.explicit]p4: + // For a given set of template parameters, if an explicit + // instantiation of a template appears after a declaration of + // an explicit specialization for that template, the explicit + // instantiation has no effect. + // + // In C++98/03 mode, we only give an extension warning here, because it + // is not not harmful to try to explicitly instantiate something that + // has been explicitly specialized. + if (!S.getLangOptions().CPlusPlus0x) { + S.Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) + << PrevDecl; + S.Diag(PrevDecl->getLocation(), + diag::note_previous_template_specialization); + } + SuppressNew = true; + return false; + + case TSK_ExplicitInstantiationDeclaration: + // We're explicity instantiating a definition for something for which we + // were previously asked to suppress instantiations. That's fine. + return false; + + case TSK_ExplicitInstantiationDefinition: + // C++0x [temp.spec]p5: + // For a given template and a given set of template-arguments, + // - an explicit instantiation definition shall appear at most once + // in a program, + S.Diag(NewLoc, diag::err_explicit_instantiation_duplicate) + << PrevDecl; + S.Diag(PrevPointOfInstantiation, + diag::note_previous_explicit_instantiation); + SuppressNew = true; + return false; + } + break; + } + + assert(false && "Missing specialization/instantiation case?"); + + return false; +} + /// \brief Perform semantic analysis for the given function template /// specialization. /// @@ -3463,54 +3657,18 @@ Sema::ActOnExplicitInstantiation(Scope *S, ClassTemplateSpecializationDecl *Specialization = 0; - bool SpecializationRequiresInstantiation = true; if (PrevDecl) { - if (PrevDecl->getSpecializationKind() - == TSK_ExplicitInstantiationDefinition) { - // This particular specialization has already been declared or - // instantiated. We cannot explicitly instantiate it. - Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate) - << Context.getTypeDeclType(PrevDecl); - Diag(PrevDecl->getLocation(), - diag::note_previous_explicit_instantiation); + bool SuppressNew = false; + if (CheckSpecializationInstantiationRedecl(*this, TemplateNameLoc, TSK, + PrevDecl, + PrevDecl->getSpecializationKind(), + PrevDecl->getPointOfInstantiation(), + SuppressNew)) return DeclPtrTy::make(PrevDecl); - } - - if (PrevDecl->getSpecializationKind() == TSK_ExplicitSpecialization) { - // C++ DR 259, C++0x [temp.explicit]p4: - // For a given set of template parameters, if an explicit - // instantiation of a template appears after a declaration of - // an explicit specialization for that template, the explicit - // instantiation has no effect. - if (!getLangOptions().CPlusPlus0x) { - Diag(TemplateNameLoc, - diag::ext_explicit_instantiation_after_specialization) - << Context.getTypeDeclType(PrevDecl); - Diag(PrevDecl->getLocation(), - diag::note_previous_template_specialization); - } - // Create a new class template specialization declaration node - // for this explicit specialization. This node is only used to - // record the existence of this explicit instantiation for - // accurate reproduction of the source code; we don't actually - // use it for anything, since it is semantically irrelevant. - Specialization - = ClassTemplateSpecializationDecl::Create(Context, - ClassTemplate->getDeclContext(), - TemplateNameLoc, - ClassTemplate, - Converted, 0); - Specialization->setLexicalDeclContext(CurContext); - CurContext->addDecl(Specialization); + if (SuppressNew) return DeclPtrTy::make(PrevDecl); - } - - // If we have already (implicitly) instantiated this - // specialization, there is less work to do. - if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation) - SpecializationRequiresInstantiation = false; - + if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation || PrevDecl->getSpecializationKind() == TSK_Undeclared) { // Since the only prior class template specialization with these @@ -3521,7 +3679,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->setLocation(TemplateNameLoc); PrevDecl = 0; } - } + } if (!Specialization) { // Create a new class template specialization declaration node for @@ -3574,11 +3732,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, // // This check comes when we actually try to perform the // instantiation. - if (SpecializationRequiresInstantiation) + ClassTemplateSpecializationDecl *Def + = cast_or_null<ClassTemplateSpecializationDecl>( + Specialization->getDefinition(Context)); + if (!Def) InstantiateClassTemplateSpecialization(Specialization, TSK); else // Instantiate the members of this class template specialization. - InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization, - TSK); + InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); return DeclPtrTy::make(Specialization); } @@ -3649,17 +3809,46 @@ Sema::ActOnExplicitInstantiation(Scope *S, // // This is C++ DR 275. CheckExplicitInstantiationScope(*this, Record, NameLoc, true); - - if (!Record->getDefinition(Context)) { - // If the class has a definition, instantiate it (and all of its - // members, recursively). - Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); - if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern, - getTemplateInstantiationArgs(Record), - TSK)) + + // Verify that it is okay to explicitly instantiate here. + CXXRecordDecl *PrevDecl + = cast_or_null<CXXRecordDecl>(Record->getPreviousDeclaration()); + if (!PrevDecl && Record->getDefinition(Context)) + PrevDecl = Record; + if (PrevDecl) { + MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo(); + bool SuppressNew = false; + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(*this, TemplateLoc, TSK, + PrevDecl, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew)) + return true; + if (SuppressNew) + return TagD; + } + + CXXRecordDecl *RecordDef + = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context)); + 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)); + if (!Def) { + Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member) + << 0 << Record->getDeclName() << Record->getDeclContext(); + Diag(Pattern->getLocation(), diag::note_forward_declaration) + << Pattern; + return true; + } else if (InstantiateClass(NameLoc, Record, Def, + getTemplateInstantiationArgs(Record), + TSK)) return true; } else // Instantiate all of the members of the class. - InstantiateClassMembers(TemplateLoc, Record, + InstantiateClassMembers(NameLoc, RecordDef, getTemplateInstantiationArgs(Record), TSK); // FIXME: We don't have any representation for explicit instantiations of @@ -3775,11 +3964,24 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // Check the scope of this explicit instantiation. CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true); + // Verify that it is okay to explicitly instantiate here. + MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo(); + assert(MSInfo && "Missing static data member specialization info?"); + bool SuppressNew = false; + if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, + Prev, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew)) + return true; + if (SuppressNew) + return DeclPtrTy(); + // Instantiate static data member. - // FIXME: Check for prior specializations and such. - Prev->setTemplateSpecializationKind(TSK); + Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (TSK == TSK_ExplicitInstantiationDefinition) - InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false); + InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false, + /*DefinitionRequired=*/true); // FIXME: Create an ExplicitInstantiation node? return DeclPtrTy(); @@ -3850,8 +4052,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!Specialization) return true; - switch (Specialization->getTemplateSpecializationKind()) { - case TSK_Undeclared: + if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_member_function_not_instantiated) << Specialization @@ -3859,35 +4060,33 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TSK_ExplicitSpecialization); Diag(Specialization->getLocation(), diag::note_explicit_instantiation_here); return true; + } + + FunctionDecl *PrevDecl = Specialization->getPreviousDeclaration(); + if (!PrevDecl && Specialization->isThisDeclarationADefinition()) + PrevDecl = Specialization; - case TSK_ExplicitSpecialization: - // C++ [temp.explicit]p4: - // For a given set of template parameters, if an explicit instantiation - // of a template appears after a declaration of an explicit - // specialization for that template, the explicit instantiation has no - // effect. - break; - - case TSK_ExplicitInstantiationDefinition: - // FIXME: Check that we aren't trying to perform an explicit instantiation - // declaration now. - // Fall through - - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - // Instantiate the function, if this is an explicit instantiation - // definition. - if (TSK == TSK_ExplicitInstantiationDefinition) - InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, - false); - - Specialization->setTemplateSpecializationKind(TSK); - break; + if (PrevDecl) { + bool SuppressNew = false; + if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, + PrevDecl, + PrevDecl->getTemplateSpecializationKind(), + PrevDecl->getPointOfInstantiation(), + SuppressNew)) + return true; + + // FIXME: We may still want to build some representation of this + // explicit specialization. + if (SuppressNew) + return DeclPtrTy(); } - - // Check the scope of this explicit instantiation. - FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); + if (TSK == TSK_ExplicitInstantiationDefinition) + InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, + false, /*DefinitionRequired=*/true); + + Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); + // C++0x [temp.explicit]p2: // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of @@ -3895,6 +4094,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // name shall be a simple-template-id. // // C++98 has the same restriction, just worded differently. + FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); if (D.getKind() != Declarator::DK_TemplateId && !FunTmpl && D.getCXXScopeSpec().isSet() && !ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) @@ -4089,12 +4289,27 @@ namespace { /// \brief Transforms a typename type by determining whether the type now /// refers to a member of the current instantiation, and then /// type-checking and building a QualifiedNameType (when possible). - QualType TransformTypenameType(const TypenameType *T); + QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL); + QualType TransformTypenameType(TypenameType *T); }; } QualType -CurrentInstantiationRebuilder::TransformTypenameType(const TypenameType *T) { +CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, + TypenameTypeLoc TL) { + QualType Result = TransformTypenameType(TL.getTypePtr()); + if (Result.isNull()) + return QualType(); + + TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; +} + +QualType +CurrentInstantiationRebuilder::TransformTypenameType(TypenameType *T) { + NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), /*FIXME:*/SourceRange(getBaseLocation())); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index b981389d1d15..2a44f83598e8 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -221,7 +221,7 @@ DeduceTemplateArguments(ASTContext &Context, QualType Arg, Sema::TemplateDeductionInfo &Info, llvm::SmallVectorImpl<TemplateArgument> &Deduced) { - assert(Arg->isCanonical() && "Argument type must be canonical"); + assert(Arg.isCanonical() && "Argument type must be canonical"); // Check whether the template argument is a dependent template-id. // FIXME: This is untested code; it can be tested when we implement @@ -313,7 +313,7 @@ DeduceTemplateArguments(ASTContext &Context, /// that corresponds to T. Otherwise, returns T. static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T, Qualifiers &Quals) { - assert(T->isCanonical() && "Only operates on canonical types"); + assert(T.isCanonical() && "Only operates on canonical types"); if (!isa<ArrayType>(T)) { Quals = T.getQualifiers(); return T.getUnqualifiedType(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 24b83704eba9..53d158088c8e 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -400,6 +400,10 @@ namespace { /// instantiating it. Decl *TransformDefinition(Decl *D); + /// \bried Transform the first qualifier within a scope by instantiating the + /// declaration. + NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc); + /// \brief Rebuild the exception declaration and register the declaration /// as an instantiated local. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, @@ -416,7 +420,8 @@ namespace { /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. - QualType TransformTemplateTypeParmType(const TemplateTypeParmType *T); + QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL); }; } @@ -457,6 +462,31 @@ Decl *TemplateInstantiator::TransformDefinition(Decl *D) { return Inst; } +NamedDecl * +TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, + SourceLocation Loc) { + // If the first part of the nested-name-specifier was a template type + // parameter, instantiate that type parameter down to a tag type. + if (TemplateTypeParmDecl *TTPD = dyn_cast_or_null<TemplateTypeParmDecl>(D)) { + const TemplateTypeParmType *TTP + = cast<TemplateTypeParmType>(getSema().Context.getTypeDeclType(TTPD)); + if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType(); + if (T.isNull()) + return cast_or_null<NamedDecl>(TransformDecl(D)); + + if (const TagType *Tag = T->getAs<TagType>()) + return Tag->getDecl(); + + // The resulting type is not a tag; complain. + getSema().Diag(Loc, diag::err_nested_name_spec_non_tag) << T; + return 0; + } + } + + return cast_or_null<NamedDecl>(TransformDecl(D)); +} + VarDecl * TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, @@ -596,8 +626,9 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { } QualType -TemplateInstantiator::TransformTemplateTypeParmType( - const TemplateTypeParmType *T) { +TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL) { + TemplateTypeParmType *T = TL.getTypePtr(); if (T->getDepth() < TemplateArgs.getNumLevels()) { // Replace the template type parameter with its corresponding // template argument. @@ -606,25 +637,42 @@ TemplateInstantiator::TransformTemplateTypeParmType( // because we are performing instantiation from explicitly-specified // template arguments in a function template class, but there were some // arguments left unspecified. - if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex())) - return QualType(T, 0); + if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex())) { + TemplateTypeParmTypeLoc NewTL + = TLB.push<TemplateTypeParmTypeLoc>(TL.getType()); + NewTL.setNameLoc(TL.getNameLoc()); + return TL.getType(); + } assert(TemplateArgs(T->getDepth(), T->getIndex()).getKind() == TemplateArgument::Type && "Template argument kind mismatch"); - return TemplateArgs(T->getDepth(), T->getIndex()).getAsType(); + QualType Replacement + = TemplateArgs(T->getDepth(), T->getIndex()).getAsType(); + + // TODO: only do this uniquing once, at the start of instantiation. + QualType Result + = getSema().Context.getSubstTemplateTypeParmType(T, Replacement); + SubstTemplateTypeParmTypeLoc NewTL + = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; } // The template type parameter comes from an inner template (e.g., // the template parameter list of a member template inside the // template we are instantiating). Create a new template type // parameter with the template "level" reduced by one. - return getSema().Context.getTemplateTypeParmType( - T->getDepth() - TemplateArgs.getNumLevels(), - T->getIndex(), - T->isParameterPack(), - T->getName()); + QualType Result + = getSema().Context.getTemplateTypeParmType(T->getDepth() + - TemplateArgs.getNumLevels(), + T->getIndex(), + T->isParameterPack(), + T->getName()); + TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; } /// \brief Perform substitution on the type T with a given set of template @@ -654,6 +702,22 @@ TemplateInstantiator::TransformTemplateTypeParmType( /// /// \returns If the instantiation succeeds, the instantiated /// type. Otherwise, produces diagnostics and returns a NULL type. +DeclaratorInfo *Sema::SubstType(DeclaratorInfo *T, + const MultiLevelTemplateArgumentList &Args, + SourceLocation Loc, + DeclarationName Entity) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + + if (!T->getType()->isDependentType()) + return T; + + TemplateInstantiator Instantiator(*this, Args, Loc, Entity); + return Instantiator.TransformType(T); +} + +/// Deprecated form of the above. QualType Sema::SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity) { @@ -769,6 +833,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, } Pattern = PatternDef; + // \brief Record the point of instantiation. + if (MemberSpecializationInfo *MSInfo + = Instantiation->getMemberSpecializationInfo()) { + MSInfo->setTemplateSpecializationKind(TSK); + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } + InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst) return true; @@ -1007,7 +1078,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, TSK_ExplicitSpecialization) continue; - Function->setTemplateSpecializationKind(TSK); + Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); } if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition) @@ -1018,7 +1089,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) continue; - Var->setTemplateSpecializationKind(TSK); + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 060cc559833f..be4adbc93d15 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -123,16 +123,17 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Do substitution on the type of the declaration - QualType T = SemaRef.SubstType(D->getType(), TemplateArgs, - D->getTypeSpecStartLoc(), - D->getDeclName()); - if (T.isNull()) + DeclaratorInfo *DI = SemaRef.SubstType(D->getDeclaratorInfo(), + TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName()); + if (!DI) return 0; // Build the instantiated declaration VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), - T, D->getDeclaratorInfo(), + DI->getType(), DI, D->getStorageClass()); Var->setThreadSpecified(D->isThreadSpecified()); Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); @@ -203,11 +204,14 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; - QualType T = D->getType(); - if (T->isDependentType()) { - T = SemaRef.SubstType(T, TemplateArgs, - D->getLocation(), D->getDeclName()); - if (!T.isNull() && T->isFunctionType()) { + DeclaratorInfo *DI = D->getDeclaratorInfo(); + if (DI->getType()->isDependentType()) { + DI = SemaRef.SubstType(DI, TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!DI) { + DI = D->getDeclaratorInfo(); + Invalid = true; + } else if (DI->getType()->isFunctionType()) { // C++ [temp.arg.type]p3: // If a declaration acquires a function type through a type // dependent on a template-parameter and this causes a @@ -215,8 +219,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { // function declarator to have function type, the program is // ill-formed. SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function) - << T; - T = QualType(); + << DI->getType(); Invalid = true; } } @@ -237,8 +240,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { BitWidth = InstantiatedBitWidth.takeAs<Expr>(); } - FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T, - D->getDeclaratorInfo(), + FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), + DI->getType(), DI, cast<RecordDecl>(Owner), D->getLocation(), D->isMutable(), @@ -1044,9 +1047,14 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, /// /// \param Recursive if true, recursively instantiates any functions that /// are required by this instantiation. +/// +/// \param DefinitionRequired if true, then we are performing an explicit +/// instantiation where the body of the function is required. Complain if +/// there is no such body. void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, - bool Recursive) { + bool Recursive, + bool DefinitionRequired) { if (Function->isInvalidDecl()) return; @@ -1075,8 +1083,24 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl) Pattern = PatternDecl->getBody(PatternDecl); - if (!Pattern) + if (!Pattern) { + if (DefinitionRequired) { + if (Function->getPrimaryTemplate()) + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_func_template) + << Function->getPrimaryTemplate(); + else + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << 1 << Function->getDeclName() << Function->getDeclContext(); + + if (PatternDecl) + Diag(PatternDecl->getLocation(), + diag::note_explicit_instantiation_here); + } + return; + } // C++0x [temp.explicit]p9: // Except for inline functions, other explicit instantiation declarations @@ -1161,10 +1185,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, /// /// \param Recursive if true, recursively instantiates any functions that /// are required by this instantiation. +/// +/// \param DefinitionRequired if true, then we are performing an explicit +/// instantiation where an out-of-line definition of the member variable +/// is required. Complain if there is no such definition. void Sema::InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, - bool Recursive) { + bool Recursive, + bool DefinitionRequired) { if (Var->isInvalidDecl()) return; @@ -1187,6 +1216,13 @@ void Sema::InstantiateStaticDataMemberDefinition( // so we won't perform any instantiation. Rather, we rely on the user to // instantiate this definition (or provide a specialization for it) in // another translation unit. + if (DefinitionRequired) { + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << 2 << Var->getDeclName() << Var->getDeclContext(); + Diag(Def->getLocation(), diag::note_explicit_instantiation_here); + } + return; } @@ -1225,7 +1261,10 @@ void Sema::InstantiateStaticDataMemberDefinition( if (Var) { Var->setPreviousDeclaration(OldVar); - Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind()); + MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo(); + assert(MSInfo && "Missing member specialization information?"); + Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation()); DeclGroupRef DG(Var); Consumer.HandleTopLevelDecl(DG); } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 9603ca8a51c4..49f7119c8b06 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/AST/Expr.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Parse/DeclSpec.h" @@ -51,16 +52,14 @@ QualType Sema::adjustParameterType(QualType T) { /// object. /// \param DS the declaration specifiers /// \param DeclLoc The location of the declarator identifier or invalid if none. -/// \param SourceTy QualType representing the type as written in source form. /// \returns The type described by the declaration specifiers. This function /// never returns null. QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, - bool &isInvalid, QualType &SourceTy) { + bool &isInvalid) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. QualType Result; - SourceTy = Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_void: @@ -105,9 +104,6 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - SourceTy = Context.getObjCProtocolListType(QualType(), - (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); @@ -225,9 +221,6 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Result = GetTypeFromParser(DS.getTypeRep()); if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - SourceTy = Context.getObjCProtocolListType(Result, - (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); if (const ObjCInterfaceType * Interface = Result->getAs<ObjCInterfaceType>()) { // It would be nice if protocol qualifiers were only stored with the @@ -384,8 +377,6 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Result = Context.getQualifiedType(Result, Quals); } - if (SourceTy.isNull()) - SourceTy = Result; return Result; } @@ -449,36 +440,32 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, /// /// \returns A suitable reference type, if there are no /// errors. Otherwise, returns a NULL type. -QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR, - SourceLocation Loc, DeclarationName Entity) { +QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, + unsigned CVR, SourceLocation Loc, + DeclarationName Entity) { Qualifiers Quals = Qualifiers::fromCVRMask(CVR); - if (LValueRef) { - if (const RValueReferenceType *R = T->getAs<RValueReferenceType>()) { - // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a - // reference to a type T, and attempt to create the type "lvalue - // reference to cv TD" creates the type "lvalue reference to T". - // We use the qualifiers (restrict or none) of the original reference, - // not the new ones. This is consistent with GCC. - QualType LVRT = Context.getLValueReferenceType(R->getPointeeType()); - return Context.getQualifiedType(LVRT, T.getQualifiers()); - } - } - if (T->isReferenceType()) { - // C++ [dcl.ref]p4: There shall be no references to references. - // - // According to C++ DR 106, references to references are only - // diagnosed when they are written directly (e.g., "int & &"), - // but not when they happen via a typedef: - // - // typedef int& intref; - // typedef intref& intref2; - // - // Parser::ParseDeclaratorInternal diagnoses the case where - // references are written directly; here, we handle the - // collapsing of references-to-references as described in C++ - // DR 106 and amended by C++ DR 540. - return T; - } + + bool LValueRef = SpelledAsLValue || T->getAs<LValueReferenceType>(); + + // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a + // reference to a type T, and attempt to create the type "lvalue + // reference to cv TD" creates the type "lvalue reference to T". + // We use the qualifiers (restrict or none) of the original reference, + // not the new ones. This is consistent with GCC. + + // C++ [dcl.ref]p4: There shall be no references to references. + // + // According to C++ DR 106, references to references are only + // diagnosed when they are written directly (e.g., "int & &"), + // but not when they happen via a typedef: + // + // typedef int& intref; + // typedef intref& intref2; + // + // Parser::ParseDeclaratorInternal diagnoses the case where + // references are written directly; here, we handle the + // collapsing of references-to-references as described in C++ + // DR 106 and amended by C++ DR 540. // C++ [dcl.ref]p1: // A declarator that specifies the type "reference to cv void" @@ -510,7 +497,8 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR, // Handle restrict on references. if (LValueRef) - return Context.getQualifiedType(Context.getLValueReferenceType(T), Quals); + return Context.getQualifiedType( + Context.getLValueReferenceType(T, SpelledAsLValue), Quals); return Context.getQualifiedType(Context.getRValueReferenceType(T), Quals); } @@ -610,8 +598,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, << ArraySize->getSourceRange(); } } - T = Context.getConstantArrayWithExprType(T, ConstVal, ArraySize, - ASM, Quals, Brackets); + T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); } // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOptions().C99) { @@ -717,7 +704,7 @@ QualType Sema::BuildFunctionType(QualType T, Invalid = true; } - ParamTypes[Idx] = adjustFunctionParamType(ParamType); + ParamTypes[Idx] = ParamType; } if (Invalid) @@ -856,9 +843,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; - // The QualType referring to the type as written in source code. We can't use - // T because it can change due to semantic analysis. - QualType SourceTy; switch (D.getKind()) { case Declarator::DK_Abstract: @@ -872,7 +856,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = Context.DependentTy; } else { bool isInvalid = false; - T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid, SourceTy); + T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid); if (isInvalid) D.setInvalidType(true); else if (OwnedDecl && DS.isTypeSpecOwned()) @@ -891,9 +875,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } - if (SourceTy.isNull()) - SourceTy = T; - if (T == Context.UndeducedAutoTy) { int Error = -1; @@ -942,8 +923,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.getIdentifier()) Name = D.getIdentifier(); - bool ShouldBuildInfo = DInfo != 0; - // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -952,17 +931,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::BlockPointer: - if (ShouldBuildInfo) { - if (SourceTy->isFunctionType()) - SourceTy - = Context.getQualifiedType(Context.getBlockPointerType(SourceTy), - Qualifiers::fromCVRMask(DeclType.Cls.TypeQuals)); - else - // If not function type Context::getBlockPointerType asserts, - // so just give up. - ShouldBuildInfo = false; - } - // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(DeclType.Loc, diag::err_blocks_disable); @@ -971,10 +939,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Name); break; case DeclaratorChunk::Pointer: - //FIXME: Use ObjCObjectPointer for info when appropriate. - if (ShouldBuildInfo) - SourceTy = Context.getQualifiedType(Context.getPointerType(SourceTy), - Qualifiers::fromCVRMask(DeclType.Ptr.TypeQuals)); // Verify that we're not building a pointer to pointer to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -995,14 +959,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Qualifiers Quals; if (DeclType.Ref.HasRestrict) Quals.addRestrict(); - if (ShouldBuildInfo) { - if (DeclType.Ref.LValueRef) - SourceTy = Context.getLValueReferenceType(SourceTy); - else - SourceTy = Context.getRValueReferenceType(SourceTy); - SourceTy = Context.getQualifiedType(SourceTy, Quals); - } - // Verify that we're not building a reference to pointer to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -1015,11 +971,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } case DeclaratorChunk::Array: { - if (ShouldBuildInfo) - // We just need to get an array type, the exact type doesn't matter. - SourceTy = Context.getIncompleteArrayType(SourceTy, ArrayType::Normal, - DeclType.Arr.TypeQuals); - // Verify that we're not building an array of pointers to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -1051,24 +1002,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } case DeclaratorChunk::Function: { - if (ShouldBuildInfo) { - const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - llvm::SmallVector<QualType, 16> ArgTys; - - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>(); - if (Param) { - QualType ArgTy = adjustFunctionParamType(Param->getType()); - - ArgTys.push_back(ArgTy); - } - } - SourceTy = Context.getFunctionType(SourceTy, ArgTys.data(), - ArgTys.size(), - FTI.isVariadic, - FTI.TypeQuals); - } - // If the function declarator has a prototype (i.e. it is not () and // does not have a K&R-style identifier list), then the arguments are part // of the type, otherwise the argument list is (). @@ -1137,6 +1070,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } else if (FTI.ArgInfo[0].Param == 0) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition. Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); + D.setInvalidType(true); } else { // Otherwise, we have a function with an argument list that is // potentially variadic. @@ -1185,7 +1119,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } - ArgTys.push_back(adjustFunctionParamType(ArgTy)); + ArgTys.push_back(ArgTy); } llvm::SmallVector<QualType, 4> Exceptions; @@ -1234,13 +1168,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, D.setInvalidType(true); } - if (ShouldBuildInfo) { - QualType cls = !ClsType.isNull() ? ClsType : Context.IntTy; - SourceTy = Context.getQualifiedType( - Context.getMemberPointerType(SourceTy, cls.getTypePtr()), - Qualifiers::fromCVRMask(DeclType.Mem.TypeQuals)); - } - if (!ClsType.isNull()) T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals, DeclType.Loc, D.getIdentifier()); @@ -1293,106 +1220,162 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (const AttributeList *Attrs = D.getAttributes()) ProcessTypeAttributeList(T, Attrs); - if (ShouldBuildInfo) - *DInfo = GetDeclaratorInfoForDeclarator(D, SourceTy, Skip); + if (DInfo) { + if (D.isInvalidType()) + *DInfo = 0; + else + *DInfo = GetDeclaratorInfoForDeclarator(D, T, Skip); + } return T; } -static void FillTypeSpecLoc(TypeLoc TSL, const DeclSpec &DS) { - if (TSL.isNull()) return; +namespace { + class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> { + const DeclSpec &DS; - if (TypedefLoc *TL = dyn_cast<TypedefLoc>(&TSL)) { - TL->setNameLoc(DS.getTypeSpecTypeLoc()); + public: + TypeSpecLocFiller(const DeclSpec &DS) : DS(DS) {} - } else if (ObjCInterfaceLoc *TL = dyn_cast<ObjCInterfaceLoc>(&TSL)) { - TL->setNameLoc(DS.getTypeSpecTypeLoc()); + void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + Visit(TL.getUnqualifiedLoc()); + } + void VisitTypedefTypeLoc(TypedefTypeLoc TL) { + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + } + void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + + if (DS.getProtocolQualifiers()) { + assert(TL.getNumProtocols() > 0); + assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); + TL.setLAngleLoc(DS.getProtocolLAngleLoc()); + TL.setRAngleLoc(DS.getSourceRange().getEnd()); + for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) + TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); + } else { + assert(TL.getNumProtocols() == 0); + TL.setLAngleLoc(SourceLocation()); + TL.setRAngleLoc(SourceLocation()); + } + } + void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); - } else if (ObjCProtocolListLoc *PLL = dyn_cast<ObjCProtocolListLoc>(&TSL)) { - assert(PLL->getNumProtocols() == DS.getNumProtocolQualifiers()); - PLL->setLAngleLoc(DS.getProtocolLAngleLoc()); - PLL->setRAngleLoc(DS.getSourceRange().getEnd()); - for (unsigned i = 0; i != DS.getNumProtocolQualifiers(); ++i) - PLL->setProtocolLoc(i, DS.getProtocolLocs()[i]); - FillTypeSpecLoc(PLL->getBaseTypeLoc(), DS); + TL.setStarLoc(SourceLocation()); - } else { - //FIXME: Other typespecs. - DefaultTypeSpecLoc &DTL = cast<DefaultTypeSpecLoc>(TSL); - DTL.setStartLoc(DS.getSourceRange().getBegin()); - } -} + if (DS.getProtocolQualifiers()) { + assert(TL.getNumProtocols() > 0); + assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); + TL.setHasProtocolsAsWritten(true); + TL.setLAngleLoc(DS.getProtocolLAngleLoc()); + TL.setRAngleLoc(DS.getSourceRange().getEnd()); + for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) + TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); -/// \brief Create and instantiate a DeclaratorInfo with type source information. -/// -/// \param T QualType referring to the type as written in source code. -DeclaratorInfo * -Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, unsigned Skip) { - DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T); - TypeLoc CurrTL = DInfo->getTypeLoc(); + } else { + assert(TL.getNumProtocols() == 0); + TL.setHasProtocolsAsWritten(false); + TL.setLAngleLoc(SourceLocation()); + TL.setRAngleLoc(SourceLocation()); + } - for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { - assert(!CurrTL.isNull()); - - // Don't bother recording source locations for qualifiers. - CurrTL = CurrTL.getUnqualifiedLoc(); + // This might not have been written with an inner type. + if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { + TL.setHasBaseTypeAsWritten(false); + TL.getBaseTypeLoc().initialize(SourceLocation()); + } else { + TL.setHasBaseTypeAsWritten(true); + Visit(TL.getBaseTypeLoc()); + } + } + void VisitTypeLoc(TypeLoc TL) { + // FIXME: add other typespec types and change this to an assert. + TL.initialize(DS.getTypeSpecTypeLoc()); + } + }; - DeclaratorChunk &DeclType = D.getTypeObject(i); - switch (DeclType.Kind) { - default: assert(0 && "Unknown decltype!"); - case DeclaratorChunk::BlockPointer: { - BlockPointerLoc &BPL = cast<BlockPointerLoc>(CurrTL); - BPL.setCaretLoc(DeclType.Loc); - break; + class DeclaratorLocFiller : public TypeLocVisitor<DeclaratorLocFiller> { + const DeclaratorChunk &Chunk; + + public: + DeclaratorLocFiller(const DeclaratorChunk &Chunk) : Chunk(Chunk) {} + + void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + llvm::llvm_unreachable("qualified type locs not expected here!"); } - case DeclaratorChunk::Pointer: { - //FIXME: ObjCObject pointers. - PointerLoc &PL = cast<PointerLoc>(CurrTL); - PL.setStarLoc(DeclType.Loc); - break; + + void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::BlockPointer); + TL.setCaretLoc(Chunk.Loc); } - case DeclaratorChunk::Reference: { - ReferenceLoc &RL = cast<ReferenceLoc>(CurrTL); - RL.setAmpLoc(DeclType.Loc); - break; + void VisitPointerTypeLoc(PointerTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Pointer); + TL.setStarLoc(Chunk.Loc); } - case DeclaratorChunk::Array: { - DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; - ArrayLoc &AL = cast<ArrayLoc>(CurrTL); - AL.setLBracketLoc(DeclType.Loc); - AL.setRBracketLoc(DeclType.EndLoc); - AL.setSizeExpr(static_cast<Expr*>(ATI.NumElts)); - //FIXME: Star location for [*]. - break; + void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Pointer); + TL.setStarLoc(Chunk.Loc); + TL.setHasBaseTypeAsWritten(true); + TL.setHasProtocolsAsWritten(false); + TL.setLAngleLoc(SourceLocation()); + TL.setRAngleLoc(SourceLocation()); } - case DeclaratorChunk::Function: { - const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - FunctionLoc &FL = cast<FunctionLoc>(CurrTL); - FL.setLParenLoc(DeclType.Loc); - FL.setRParenLoc(DeclType.EndLoc); - for (unsigned i = 0, e = FTI.NumArgs, tpi = 0; i != e; ++i) { + void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::MemberPointer); + TL.setStarLoc(Chunk.Loc); + // FIXME: nested name specifier + } + void VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Reference); + // 'Amp' is misleading: this might have been originally + /// spelled with AmpAmp. + TL.setAmpLoc(Chunk.Loc); + } + void VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Reference); + assert(!Chunk.Ref.LValueRef); + TL.setAmpAmpLoc(Chunk.Loc); + } + void VisitArrayTypeLoc(ArrayTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Array); + TL.setLBracketLoc(Chunk.Loc); + TL.setRBracketLoc(Chunk.EndLoc); + TL.setSizeExpr(static_cast<Expr*>(Chunk.Arr.NumElts)); + } + void VisitFunctionTypeLoc(FunctionTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Function); + TL.setLParenLoc(Chunk.Loc); + TL.setRParenLoc(Chunk.EndLoc); + + const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun; + for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) { ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>(); - if (Param) { - assert(tpi < FL.getNumArgs()); - FL.setArg(tpi++, Param); - } + TL.setArg(tpi++, Param); } - break; - //FIXME: Exception specs. - } - case DeclaratorChunk::MemberPointer: { - MemberPointerLoc &MPL = cast<MemberPointerLoc>(CurrTL); - MPL.setStarLoc(DeclType.Loc); - //FIXME: Class location. - break; + // FIXME: exception specs } + void VisitTypeLoc(TypeLoc TL) { + llvm::llvm_unreachable("unsupported TypeLoc kind in declarator!"); } + }; +} + +/// \brief Create and instantiate a DeclaratorInfo with type source information. +/// +/// \param T QualType referring to the type as written in source code. +DeclaratorInfo * +Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, unsigned Skip) { + DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T); + UnqualTypeLoc CurrTL = DInfo->getTypeLoc().getUnqualifiedLoc(); - CurrTL = CurrTL.getNextTypeLoc(); + for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { + DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL); + CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); } - FillTypeSpecLoc(CurrTL, D.getDeclSpec()); + TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL); return DInfo; } @@ -1655,6 +1638,8 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, PartialDiagnostic> Note) { unsigned diag = PD.getDiagID(); + // FIXME: Add this assertion to make sure we always get instantiation points. + // assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType"); // FIXME: Add this assertion to help us flush out problems with // checking for dependent types and type-dependent expressions. // diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ec5c6676f5d2..7e0972fe03c4 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1,4 +1,4 @@ -//===------- TreeTransform.h - Semantic Tree Transformation ---------------===/ +//===------- TreeTransform.h - Semantic Tree Transformation -----*- C++ -*-===/ // // The LLVM Compiler Infrastructure // @@ -22,9 +22,11 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/TypeLocBuilder.h" #include "clang/Parse/Ownership.h" #include "clang/Parse/Designator.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/Support/ErrorHandling.h" #include <algorithm> namespace clang { @@ -170,25 +172,30 @@ public: /// \brief Transforms the given type into another type. /// - /// By default, this routine transforms a type by delegating to the - /// appropriate TransformXXXType to build a new type, then applying - /// the qualifiers on \p T to the resulting type with AddTypeQualifiers. - /// Subclasses may override this function (to take over all type - /// transformations), some set of the TransformXXXType functions, or - /// the AddTypeQualifiers function to alter the transformation. + /// By default, this routine transforms a type by creating a + /// DeclaratorInfo for it and delegating to the appropriate + /// function. This is expensive, but we don't mind, because + /// this method is deprecated anyway; all users should be + /// switched to storing DeclaratorInfos. /// /// \returns the transformed type. QualType TransformType(QualType T); - /// \brief Transform the given type by adding the given set of qualifiers - /// and returning the result. + /// \brief Transforms the given type-with-location into a new + /// type-with-location. + /// + /// By default, this routine transforms a type by delegating to the + /// appropriate TransformXXXType to build a new type. Subclasses + /// may override this function (to take over all type + /// transformations) or some set of the TransformXXXType functions + /// to alter the transformation. + DeclaratorInfo *TransformType(DeclaratorInfo *DI); + + /// \brief Transform the given type-with-location into a new + /// type, collecting location information in the given builder + /// as necessary. /// - /// FIXME: By default, this routine adds type qualifiers only to types that - /// can have qualifiers, and silently suppresses those qualifiers that are - /// not permitted (e.g., qualifiers on reference or function types). This - /// is the right thing for template instantiation, but probably not for - /// other clients. - QualType AddTypeQualifiers(QualType T, Qualifiers Qs); + QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL); /// \brief Transform the given statement. /// @@ -236,6 +243,19 @@ public: /// Subclasses may override this function to provide alternate behavior. Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); } + /// \brief Transform the given declaration, which was the first part of a + /// nested-name-specifier in a member access expression. + /// + /// This specific declaration transformation only applies to the first + /// identifier in a nested-name-specifier of a member access expression, e.g., + /// the \c T in \c x->T::member + /// + /// By default, invokes TransformDecl() to transform the declaration. + /// Subclasses may override this function to provide alternate behavior. + NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc) { + return cast_or_null<NamedDecl>(getDerived().TransformDecl(D)); + } + /// \brief Transform the given nested-name-specifier. /// /// By default, transforms all of the types and declarations within the @@ -253,7 +273,8 @@ public: /// Identifiers and selectors are returned unmodified. Sublcasses may /// override this function to provide alternate behavior. DeclarationName TransformDeclarationName(DeclarationName Name, - SourceLocation Loc); + SourceLocation Loc, + QualType ObjectType = QualType()); /// \brief Transform the given template name. /// @@ -271,11 +292,15 @@ public: /// override this function to provide alternate behavior. TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg); -#define ABSTRACT_TYPE(CLASS, PARENT) -#define TYPE(CLASS, PARENT) \ - QualType Transform##CLASS##Type(const CLASS##Type *T); -#include "clang/AST/TypeNodes.def" +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); +#include "clang/AST/TypeLocNodes.def" + QualType + TransformTemplateSpecializationType(const TemplateSpecializationType *T, + QualType ObjectType); + OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); #define STMT(Node, Parent) \ @@ -316,6 +341,9 @@ public: /// type. Subclasses may override this routine to provide different behavior. QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType); + /// \brief Build a new Objective C object pointer type. + QualType RebuildObjCObjectPointerType(QualType PointeeType); + /// \brief Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type /// qualifiers. @@ -340,29 +368,6 @@ public: const llvm::APInt &Size, unsigned IndexTypeQuals); - /// \brief Build a new constant array type given the element type, size - /// modifier, (known) size of the array, size expression, and index type - /// qualifiers. - /// - /// By default, performs semantic analysis when building the array type. - /// Subclasses may override this routine to provide different behavior. - QualType RebuildConstantArrayWithExprType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange); - - /// \brief Build a new constant array type given the element type, size - /// modifier, (known) size of the array, and index type qualifiers. - /// - /// By default, performs semantic analysis when building the array type. - /// Subclasses may override this routine to provide different behavior. - QualType RebuildConstantArrayWithoutExprType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - unsigned IndexTypeQuals); - /// \brief Build a new incomplete array type given the element type, size /// modifier, and index type qualifiers. /// @@ -427,6 +432,9 @@ public: unsigned NumParamTypes, bool Variadic, unsigned Quals); + /// \brief Build a new unprototyped function type. + QualType RebuildFunctionNoProtoType(QualType ResultType); + /// \brief Build a new typedef type. QualType RebuildTypedefType(TypedefDecl *Typedef) { return SemaRef.Context.getTypeDeclType(Typedef); @@ -1429,13 +1437,16 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildTemplateIdExpr(TemplateName Template, + OwningExprResult RebuildTemplateIdExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TemplateName Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { - return getSema().BuildTemplateIdExpr(Template, TemplateLoc, + return getSema().BuildTemplateIdExpr(Qualifier, QualifierRange, + Template, TemplateLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc); @@ -1757,7 +1768,8 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, template<typename Derived> DeclarationName TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name, - SourceLocation Loc) { + SourceLocation Loc, + QualType ObjectType) { if (!Name) return Name; @@ -1774,7 +1786,14 @@ TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name, case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: { TemporaryBase Rebase(*this, Loc, Name); - QualType T = getDerived().TransformType(Name.getCXXNameType()); + QualType T; + if (!ObjectType.isNull() && + isa<TemplateSpecializationType>(Name.getCXXNameType())) { + TemplateSpecializationType *SpecType + = cast<TemplateSpecializationType>(Name.getCXXNameType()); + T = TransformTemplateSpecializationType(SpecType, ObjectType); + } else + T = getDerived().TransformType(Name.getCXXNameType()); if (T.isNull()) return DeclarationName(); @@ -1837,7 +1856,8 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, return TemplateName(); if (!getDerived().AlwaysRebuild() && - NNS == DTN->getQualifier()) + NNS == DTN->getQualifier() && + ObjectType.isNull()) return Name; return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType); @@ -1935,268 +1955,369 @@ QualType TreeTransform<Derived>::TransformType(QualType T) { if (getDerived().AlreadyTransformed(T)) return T; - QualifierCollector Qs; - const Type *Ty = Qs.strip(T); + // Temporary workaround. All of these transformations should + // eventually turn into transformations on TypeLocs. + DeclaratorInfo *DI = getSema().Context.CreateDeclaratorInfo(T); + DI->getTypeLoc().initialize(getDerived().getBaseLocation()); + + DeclaratorInfo *NewDI = getDerived().TransformType(DI); - QualType Result; - switch (Ty->getTypeClass()) { -#define ABSTRACT_TYPE(CLASS, PARENT) -#define TYPE(CLASS, PARENT) \ - case Type::CLASS: \ - Result = getDerived().Transform##CLASS##Type( \ - static_cast<const CLASS##Type*>(Ty)); \ - break; -#include "clang/AST/TypeNodes.def" - } - - if (Result.isNull() || T == Result) - return Result; + if (!NewDI) + return QualType(); - return getDerived().AddTypeQualifiers(Result, Qs); + return NewDI->getType(); } template<typename Derived> -QualType -TreeTransform<Derived>::AddTypeQualifiers(QualType T, Qualifiers Quals) { - if (!Quals.empty() && !T->isFunctionType() && !T->isReferenceType()) - return SemaRef.Context.getQualifiedType(T, Quals); +DeclaratorInfo *TreeTransform<Derived>::TransformType(DeclaratorInfo *DI) { + if (getDerived().AlreadyTransformed(DI->getType())) + return DI; - return T; -} + TypeLocBuilder TLB; -template<typename Derived> -QualType TreeTransform<Derived>::TransformBuiltinType(const BuiltinType *T) { - // Nothing to do - return QualType(T, 0); -} + TypeLoc TL = DI->getTypeLoc(); + TLB.reserve(TL.getFullDataSize()); -template<typename Derived> -QualType TreeTransform<Derived>::TransformFixedWidthIntType( - const FixedWidthIntType *T) { - // FIXME: Implement - return QualType(T, 0); -} + QualType Result = getDerived().TransformType(TLB, TL); + if (Result.isNull()) + return 0; -template<typename Derived> -QualType TreeTransform<Derived>::TransformComplexType(const ComplexType *T) { - // FIXME: Implement - return QualType(T, 0); + return TLB.getDeclaratorInfo(SemaRef.Context, Result); } template<typename Derived> -QualType TreeTransform<Derived>::TransformPointerType(const PointerType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType()) - return QualType(T, 0); +QualType +TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) { + switch (T.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: \ + return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T)); +#include "clang/AST/TypeLocNodes.def" + } - return getDerived().RebuildPointerType(PointeeType); + llvm::llvm_unreachable("unhandled type loc!"); + return QualType(); } +/// FIXME: By default, this routine adds type qualifiers only to types +/// that can have qualifiers, and silently suppresses those qualifiers +/// that are not permitted (e.g., qualifiers on reference or function +/// types). This is the right thing for template instantiation, but +/// probably not for other clients. template<typename Derived> QualType -TreeTransform<Derived>::TransformBlockPointerType(const BlockPointerType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) +TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, + QualifiedTypeLoc T) { + Qualifiers Quals = T.getType().getQualifiers(); + + QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc()); + if (Result.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType()) - return QualType(T, 0); + // Silently suppress qualifiers if the result type can't be qualified. + // FIXME: this is the right thing for template instantiation, but + // probably not for other clients. + if (Result->isFunctionType() || Result->isReferenceType()) + return Result; - return getDerived().RebuildBlockPointerType(PointeeType); + Result = SemaRef.Context.getQualifiedType(Result, Quals); + + TLB.push<QualifiedTypeLoc>(Result); + + // No location information to preserve. + + return Result; +} + +template <class TyLoc> static inline +QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { + TyLoc NewT = TLB.push<TyLoc>(T.getType()); + NewT.setNameLoc(T.getNameLoc()); + return T.getType(); +} + +// Ugly metaprogramming macros because I couldn't be bothered to make +// the equivalent template version work. +#define TransformPointerLikeType(TypeClass) do { \ + QualType PointeeType \ + = getDerived().TransformType(TLB, TL.getPointeeLoc()); \ + if (PointeeType.isNull()) \ + return QualType(); \ + \ + QualType Result = TL.getType(); \ + if (getDerived().AlwaysRebuild() || \ + PointeeType != TL.getPointeeLoc().getType()) { \ + Result = getDerived().Rebuild##TypeClass(PointeeType); \ + if (Result.isNull()) \ + return QualType(); \ + } \ + \ + TypeClass##Loc NewT = TLB.push<TypeClass##Loc>(Result); \ + NewT.setSigilLoc(TL.getSigilLoc()); \ + \ + return Result; \ +} while(0) + +// Reference collapsing forces us to transform reference types +// differently from the other pointer-like types. +#define TransformReferenceType(TypeClass) do { \ + QualType PointeeType \ + = getDerived().TransformType(TLB, TL.getPointeeLoc()); \ + if (PointeeType.isNull()) \ + return QualType(); \ + \ + QualType Result = TL.getType(); \ + if (getDerived().AlwaysRebuild() || \ + PointeeType != TL.getPointeeLoc().getType()) { \ + Result = getDerived().Rebuild##TypeClass(PointeeType); \ + if (Result.isNull()) \ + return QualType(); \ + } \ + \ + /* Workaround: rebuild doesn't always change the type */ \ + /* FIXME: avoid losing this location information. */ \ + if (Result == PointeeType) \ + return Result; \ + ReferenceTypeLoc NewTL; \ + if (isa<LValueReferenceType>(Result)) \ + NewTL = TLB.push<LValueReferenceTypeLoc>(Result); \ + else \ + NewTL = TLB.push<RValueReferenceTypeLoc>(Result); \ + NewTL.setSigilLoc(TL.getSigilLoc()); \ + return Result; \ +} while (0) + +template<typename Derived> +QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, + BuiltinTypeLoc T) { + return TransformTypeSpecType(TLB, T); } template<typename Derived> QualType -TreeTransform<Derived>::TransformLValueReferenceType( - const LValueReferenceType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); +TreeTransform<Derived>::TransformFixedWidthIntType(TypeLocBuilder &TLB, + FixedWidthIntTypeLoc T) { + return TransformTypeSpecType(TLB, T); +} - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType()) - return QualType(T, 0); +template<typename Derived> +QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB, + ComplexTypeLoc T) { + // FIXME: recurse? + return TransformTypeSpecType(TLB, T); +} - return getDerived().RebuildLValueReferenceType(PointeeType); +template<typename Derived> +QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, + PointerTypeLoc TL) { + TransformPointerLikeType(PointerType); } template<typename Derived> QualType -TreeTransform<Derived>::TransformRValueReferenceType( - const RValueReferenceType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType()) - return QualType(T, 0); - - return getDerived().RebuildRValueReferenceType(PointeeType); +TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, + BlockPointerTypeLoc TL) { + TransformPointerLikeType(BlockPointerType); } template<typename Derived> QualType -TreeTransform<Derived>::TransformMemberPointerType(const MemberPointerType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - QualType ClassType = getDerived().TransformType(QualType(T->getClass(), 0)); - if (ClassType.isNull()) - return QualType(); - - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType() && - ClassType == QualType(T->getClass(), 0)) - return QualType(T, 0); - - return getDerived().RebuildMemberPointerType(PointeeType, ClassType); +TreeTransform<Derived>::TransformLValueReferenceType(TypeLocBuilder &TLB, + LValueReferenceTypeLoc TL) { + TransformReferenceType(LValueReferenceType); } template<typename Derived> QualType -TreeTransform<Derived>::TransformConstantArrayType(const ConstantArrayType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); - if (ElementType.isNull()) - return QualType(); - - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); - - return getDerived().RebuildConstantArrayType(ElementType, - T->getSizeModifier(), - T->getSize(), - T->getIndexTypeCVRQualifiers()); +TreeTransform<Derived>::TransformRValueReferenceType(TypeLocBuilder &TLB, + RValueReferenceTypeLoc TL) { + TransformReferenceType(RValueReferenceType); } template<typename Derived> QualType -TreeTransform<Derived>::TransformConstantArrayWithExprType( - const ConstantArrayWithExprType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); - if (ElementType.isNull()) - return QualType(); +TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, + MemberPointerTypeLoc TL) { + MemberPointerType *T = TL.getTypePtr(); - // Array bounds are not potentially evaluated contexts - EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); + if (PointeeType.isNull()) + return QualType(); - Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); - if (Size.isInvalid()) + // TODO: preserve source information for this. + QualType ClassType + = getDerived().TransformType(QualType(T->getClass(), 0)); + if (ClassType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType() && - Size.get() == T->getSizeExpr()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + PointeeType != T->getPointeeType() || + ClassType != QualType(T->getClass(), 0)) { + Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType); + if (Result.isNull()) + return QualType(); + } - return getDerived().RebuildConstantArrayWithExprType(ElementType, - T->getSizeModifier(), - T->getSize(), - Size.takeAs<Expr>(), - T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + MemberPointerTypeLoc NewTL = TLB.push<MemberPointerTypeLoc>(Result); + NewTL.setSigilLoc(TL.getSigilLoc()); + + return Result; } template<typename Derived> QualType -TreeTransform<Derived>::TransformConstantArrayWithoutExprType( - const ConstantArrayWithoutExprType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); +TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, + ConstantArrayTypeLoc TL) { + ConstantArrayType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); - - return getDerived().RebuildConstantArrayWithoutExprType(ElementType, - T->getSizeModifier(), - T->getSize(), + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType()) { + Result = getDerived().RebuildConstantArrayType(ElementType, + T->getSizeModifier(), + T->getSize(), T->getIndexTypeCVRQualifiers()); + if (Result.isNull()) + return QualType(); + } + + ConstantArrayTypeLoc NewTL = TLB.push<ConstantArrayTypeLoc>(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + + Expr *Size = TL.getSizeExpr(); + if (Size) { + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + Size = getDerived().TransformExpr(Size).template takeAs<Expr>(); + } + NewTL.setSizeExpr(Size); + + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformIncompleteArrayType( - const IncompleteArrayType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); + TypeLocBuilder &TLB, + IncompleteArrayTypeLoc TL) { + IncompleteArrayType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType()) { + Result = getDerived().RebuildIncompleteArrayType(ElementType, + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + if (Result.isNull()) + return QualType(); + } + + IncompleteArrayTypeLoc NewTL = TLB.push<IncompleteArrayTypeLoc>(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(0); - return getDerived().RebuildIncompleteArrayType(ElementType, - T->getSizeModifier(), - T->getIndexTypeCVRQualifiers()); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformVariableArrayType( - const VariableArrayType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); +QualType +TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB, + VariableArrayTypeLoc TL) { + VariableArrayType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); // Array bounds are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); - if (Size.isInvalid()) + Sema::OwningExprResult SizeResult + = getDerived().TransformExpr(T->getSizeExpr()); + if (SizeResult.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType() && - Size.get() == T->getSizeExpr()) { - Size.take(); - return QualType(T, 0); + Expr *Size = static_cast<Expr*>(SizeResult.get()); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType() || + Size != T->getSizeExpr()) { + Result = getDerived().RebuildVariableArrayType(ElementType, + T->getSizeModifier(), + move(SizeResult), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); + if (Result.isNull()) + return QualType(); } + else SizeResult.take(); + + VariableArrayTypeLoc NewTL = TLB.push<VariableArrayTypeLoc>(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(Size); - return getDerived().RebuildVariableArrayType(ElementType, - T->getSizeModifier(), - move(Size), - T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformDependentSizedArrayType( - const DependentSizedArrayType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); +QualType +TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, + DependentSizedArrayTypeLoc TL) { + DependentSizedArrayType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); // Array bounds are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); - if (Size.isInvalid()) + Sema::OwningExprResult SizeResult + = getDerived().TransformExpr(T->getSizeExpr()); + if (SizeResult.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType() && - Size.get() == T->getSizeExpr()) { - Size.take(); - return QualType(T, 0); + Expr *Size = static_cast<Expr*>(SizeResult.get()); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType() || + Size != T->getSizeExpr()) { + Result = getDerived().RebuildDependentSizedArrayType(ElementType, + T->getSizeModifier(), + move(SizeResult), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); + if (Result.isNull()) + return QualType(); } + else SizeResult.take(); - return getDerived().RebuildDependentSizedArrayType(ElementType, - T->getSizeModifier(), - move(Size), - T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + // We might have any sort of array type now, but fortunately they + // all have the same location layout. + ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(Size); + + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( - const DependentSizedExtVectorType *T) { + TypeLocBuilder &TLB, + DependentSizedExtVectorTypeLoc TL) { + DependentSizedExtVectorType *T = TL.getTypePtr(); + + // FIXME: ext vector locs should be nested QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); @@ -2208,98 +2329,201 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( if (Size.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType() && - Size.get() == T->getSizeExpr()) { - Size.take(); - return QualType(T, 0); - } - - return getDerived().RebuildDependentSizedExtVectorType(ElementType, + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + (ElementType != T->getElementType() && Size.get() != T->getSizeExpr())) { + Result = getDerived().RebuildDependentSizedExtVectorType(ElementType, move(Size), T->getAttributeLoc()); + if (Result.isNull()) + return QualType(); + } + else Size.take(); + + // Result might be dependent or not. + if (isa<DependentSizedExtVectorType>(Result)) { + DependentSizedExtVectorTypeLoc NewTL + = TLB.push<DependentSizedExtVectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + } else { + ExtVectorTypeLoc NewTL = TLB.push<ExtVectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + } + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformVectorType(const VectorType *T) { +QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB, + VectorTypeLoc TL) { + VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType()) { + Result = getDerived().RebuildVectorType(ElementType, T->getNumElements()); + if (Result.isNull()) + return QualType(); + } + + VectorTypeLoc NewTL = TLB.push<VectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildVectorType(ElementType, T->getNumElements()); + return Result; } template<typename Derived> -QualType -TreeTransform<Derived>::TransformExtVectorType(const ExtVectorType *T) { +QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, + ExtVectorTypeLoc TL) { + VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType()) { + Result = getDerived().RebuildExtVectorType(ElementType, + T->getNumElements(), + /*FIXME*/ SourceLocation()); + if (Result.isNull()) + return QualType(); + } + + ExtVectorTypeLoc NewTL = TLB.push<ExtVectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildExtVectorType(ElementType, T->getNumElements(), - /*FIXME*/SourceLocation()); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformFunctionProtoType( - const FunctionProtoType *T) { - QualType ResultType = getDerived().TransformType(T->getResultType()); +QualType +TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL) { + FunctionProtoType *T = TL.getTypePtr(); + QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); if (ResultType.isNull()) return QualType(); + // Transform the parameters. llvm::SmallVector<QualType, 4> ParamTypes; - for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(), - ParamEnd = T->arg_type_end(); - Param != ParamEnd; ++Param) { - QualType P = getDerived().TransformType(*Param); - if (P.isNull()) - return QualType(); + llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { + ParmVarDecl *OldParm = TL.getArg(i); + + QualType NewType; + ParmVarDecl *NewParm; + + if (OldParm) { + DeclaratorInfo *OldDI = OldParm->getDeclaratorInfo(); + assert(OldDI->getType() == T->getArgType(i)); + + DeclaratorInfo *NewDI = getDerived().TransformType(OldDI); + if (!NewDI) + return QualType(); + + if (NewDI == OldDI) + NewParm = OldParm; + else + NewParm = ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + /* DefArg */ NULL); + NewType = NewParm->getType(); + + // Deal with the possibility that we don't have a parameter + // declaration for this parameter. + } else { + NewParm = 0; + + QualType OldType = T->getArgType(i); + NewType = getDerived().TransformType(OldType); + if (NewType.isNull()) + return QualType(); + } - ParamTypes.push_back(P); + ParamTypes.push_back(NewType); + ParamDecls.push_back(NewParm); } - if (!getDerived().AlwaysRebuild() && - ResultType == T->getResultType() && - std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ResultType != T->getResultType() || + !std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) { + Result = getDerived().RebuildFunctionProtoType(ResultType, + ParamTypes.data(), + ParamTypes.size(), + T->isVariadic(), + T->getTypeQuals()); + if (Result.isNull()) + return QualType(); + } + + FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i) + NewTL.setArg(i, ParamDecls[i]); - return getDerived().RebuildFunctionProtoType(ResultType, ParamTypes.data(), - ParamTypes.size(), T->isVariadic(), - T->getTypeQuals()); + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionNoProtoType( - const FunctionNoProtoType *T) { - // FIXME: Implement - return QualType(T, 0); + TypeLocBuilder &TLB, + FunctionNoProtoTypeLoc TL) { + FunctionNoProtoType *T = TL.getTypePtr(); + QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ResultType != T->getResultType()) + Result = getDerived().RebuildFunctionNoProtoType(ResultType); + + FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformTypedefType(const TypedefType *T) { +QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, + TypedefTypeLoc TL) { + TypedefType *T = TL.getTypePtr(); TypedefDecl *Typedef = cast_or_null<TypedefDecl>(getDerived().TransformDecl(T->getDecl())); if (!Typedef) return QualType(); - if (!getDerived().AlwaysRebuild() && - Typedef == T->getDecl()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Typedef != T->getDecl()) { + Result = getDerived().RebuildTypedefType(Typedef); + if (Result.isNull()) + return QualType(); + } + + TypedefTypeLoc NewTL = TLB.push<TypedefTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildTypedefType(Typedef); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformTypeOfExprType( - const TypeOfExprType *T) { +QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, + TypeOfExprTypeLoc TL) { + TypeOfExprType *T = TL.getTypePtr(); + // typeof expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); @@ -2307,30 +2531,50 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType( if (E.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - E.get() == T->getUnderlyingExpr()) { - E.take(); - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + E.get() != T->getUnderlyingExpr()) { + Result = getDerived().RebuildTypeOfExprType(move(E)); + if (Result.isNull()) + return QualType(); } + else E.take(); - return getDerived().RebuildTypeOfExprType(move(E)); + TypeOfExprTypeLoc NewTL = TLB.push<TypeOfExprTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformTypeOfType(const TypeOfType *T) { +QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, + TypeOfTypeLoc TL) { + TypeOfType *T = TL.getTypePtr(); + + // FIXME: should be an inner type, or at least have a DeclaratorInfo. QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); if (Underlying.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - Underlying == T->getUnderlyingType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Underlying != T->getUnderlyingType()) { + Result = getDerived().RebuildTypeOfType(Underlying); + if (Result.isNull()) + return QualType(); + } - return getDerived().RebuildTypeOfType(Underlying); + TypeOfTypeLoc NewTL = TLB.push<TypeOfTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformDecltypeType(const DecltypeType *T) { +QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, + DecltypeTypeLoc TL) { + DecltypeType *T = TL.getTypePtr(); + // decltype expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); @@ -2338,70 +2582,130 @@ QualType TreeTransform<Derived>::TransformDecltypeType(const DecltypeType *T) { if (E.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - E.get() == T->getUnderlyingExpr()) { - E.take(); - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + E.get() != T->getUnderlyingExpr()) { + Result = getDerived().RebuildDecltypeType(move(E)); + if (Result.isNull()) + return QualType(); } + else E.take(); - return getDerived().RebuildDecltypeType(move(E)); + DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformRecordType(const RecordType *T) { +QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB, + RecordTypeLoc TL) { + RecordType *T = TL.getTypePtr(); RecordDecl *Record - = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl())); + = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl())); if (!Record) return QualType(); - if (!getDerived().AlwaysRebuild() && - Record == T->getDecl()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Record != T->getDecl()) { + Result = getDerived().RebuildRecordType(Record); + if (Result.isNull()) + return QualType(); + } + + RecordTypeLoc NewTL = TLB.push<RecordTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildRecordType(Record); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformEnumType(const EnumType *T) { +QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB, + EnumTypeLoc TL) { + EnumType *T = TL.getTypePtr(); EnumDecl *Enum - = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl())); + = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl())); if (!Enum) return QualType(); - if (!getDerived().AlwaysRebuild() && - Enum == T->getDecl()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Enum != T->getDecl()) { + Result = getDerived().RebuildEnumType(Enum); + if (Result.isNull()) + return QualType(); + } + + EnumTypeLoc NewTL = TLB.push<EnumTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildEnumType(Enum); + return Result; } template <typename Derived> -QualType TreeTransform<Derived>::TransformElaboratedType( - const ElaboratedType *T) { +QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, + ElaboratedTypeLoc TL) { + ElaboratedType *T = TL.getTypePtr(); + + // FIXME: this should be a nested type. QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); if (Underlying.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - Underlying == T->getUnderlyingType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Underlying != T->getUnderlyingType()) { + Result = getDerived().RebuildElaboratedType(Underlying, T->getTagKind()); + if (Result.isNull()) + return QualType(); + } + + ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildElaboratedType(Underlying, T->getTagKind()); + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateTypeParmType( - const TemplateTypeParmType *T) { - // Nothing to do - return QualType(T, 0); + TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL) { + return TransformTypeSpecType(TLB, TL); } template<typename Derived> +QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType( + TypeLocBuilder &TLB, + SubstTemplateTypeParmTypeLoc TL) { + return TransformTypeSpecType(TLB, TL); +} + +template<typename Derived> +inline QualType +TreeTransform<Derived>::TransformTemplateSpecializationType( + TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL) { + // TODO: figure out how make this work with an ObjectType. + QualType Result + = TransformTemplateSpecializationType(TL.getTypePtr(), QualType()); + if (Result.isNull()) + return QualType(); + + TemplateSpecializationTypeLoc NewTL + = TLB.push<TemplateSpecializationTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateSpecializationType( - const TemplateSpecializationType *T) { + const TemplateSpecializationType *T, + QualType ObjectType) { TemplateName Template - = getDerived().TransformTemplateName(T->getTemplateName()); + = getDerived().TransformTemplateName(T->getTemplateName(), ObjectType); if (Template.isNull()) return QualType(); @@ -2426,8 +2730,10 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( } template<typename Derived> -QualType TreeTransform<Derived>::TransformQualifiedNameType( - const QualifiedNameType *T) { +QualType +TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB, + QualifiedNameTypeLoc TL) { + QualifiedNameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SourceRange()); @@ -2438,22 +2744,33 @@ QualType TreeTransform<Derived>::TransformQualifiedNameType( if (Named.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - NNS == T->getQualifier() && - Named == T->getNamedType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + NNS != T->getQualifier() || + Named != T->getNamedType()) { + Result = getDerived().RebuildQualifiedNameType(NNS, Named); + if (Result.isNull()) + return QualType(); + } + + QualifiedNameTypeLoc NewTL = TLB.push<QualifiedNameTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildQualifiedNameType(NNS, Named); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformTypenameType(const TypenameType *T) { +QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, + TypenameTypeLoc TL) { + TypenameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SourceRange(/*FIXME:*/getDerived().getBaseLocation())); if (!NNS) return QualType(); + QualType Result; + if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { QualType NewTemplateId = getDerived().TransformType(QualType(TemplateId, 0)); @@ -2465,31 +2782,33 @@ QualType TreeTransform<Derived>::TransformTypenameType(const TypenameType *T) { NewTemplateId == QualType(TemplateId, 0)) return QualType(T, 0); - return getDerived().RebuildTypenameType(NNS, NewTemplateId); + Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); + } else { + Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier()); } + if (Result.isNull()) + return QualType(); - return getDerived().RebuildTypenameType(NNS, T->getIdentifier()); -} + TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); -template<typename Derived> -QualType TreeTransform<Derived>::TransformObjCInterfaceType( - const ObjCInterfaceType *T) { - // FIXME: Implement - return QualType(T, 0); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformObjCObjectPointerType( - const ObjCObjectPointerType *T) { - // FIXME: Implement - return QualType(T, 0); +QualType +TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, + ObjCInterfaceTypeLoc TL) { + assert(false && "TransformObjCInterfaceType unimplemented"); + return QualType(); } template<typename Derived> -QualType TreeTransform<Derived>::TransformObjCProtocolListType( - const ObjCProtocolListType *T) { - assert(false && "Should not see ObjCProtocolList types"); - return QualType(T, 0); +QualType +TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, + ObjCObjectPointerTypeLoc TL) { + assert(false && "TransformObjCObjectPointerType unimplemented"); + return QualType(); } //===----------------------------------------------------------------------===// @@ -4010,8 +4329,8 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformUnresolvedDeclRefExpr( UnresolvedDeclRefExpr *E) { NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); + = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); if (!NNS) return SemaRef.ExprError(); @@ -4040,6 +4359,14 @@ TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { if (Template.isNull()) return SemaRef.ExprError(); + NestedNameSpecifier *Qualifier = 0; + if (E->getQualifier()) { + Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (!Qualifier) + return SemaRef.ExprError(); + } + llvm::SmallVector<TemplateArgument, 4> TransArgs; for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { TemplateArgument TransArg @@ -4056,7 +4383,8 @@ TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { // FIXME: It's possible that we'll find out now that the template name // actually refers to a type, in which case the caller is actually dealing // with a functional cast. Give a reasonable error message! - return getDerived().RebuildTemplateIdExpr(Template, E->getTemplateNameLoc(), + return getDerived().RebuildTemplateIdExpr(Qualifier, E->getQualifierRange(), + Template, E->getTemplateNameLoc(), E->getLAngleLoc(), TransArgs.data(), TransArgs.size(), @@ -4235,6 +4563,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( if (Base.isInvalid()) return SemaRef.ExprError(); + // Start the member reference and compute the object's type. Sema::TypeTy *ObjectType = 0; Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), E->getOperatorLoc(), @@ -4243,12 +4572,12 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( if (Base.isInvalid()) return SemaRef.ExprError(); - // FIXME: The first qualifier found might be a template type parameter, - // in which case there is no transformed declaration to refer to (it might - // refer to a built-in type!). + // Transform the first part of the nested-name-specifier that qualifies + // the member name. NamedDecl *FirstQualifierInScope - = cast_or_null<NamedDecl>( - getDerived().TransformDecl(E->getFirstQualifierFoundInScope())); + = getDerived().TransformFirstQualifierInScope( + E->getFirstQualifierFoundInScope(), + E->getQualifierRange().getBegin()); NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { @@ -4261,7 +4590,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( } DeclarationName Name - = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc()); + = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(), + QualType::getFromOpaquePtr(ObjectType)); if (!Name) return SemaRef.ExprError(); @@ -4504,6 +4834,14 @@ QualType TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, template<typename Derived> QualType +TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType) { + return SemaRef.BuildPointerType(PointeeType, Qualifiers(), + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt *Size, @@ -4549,29 +4887,6 @@ TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType, template<typename Derived> QualType -TreeTransform<Derived>::RebuildConstantArrayWithExprType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange) { - return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr, - IndexTypeQuals, BracketsRange); -} - -template<typename Derived> -QualType -TreeTransform<Derived>::RebuildConstantArrayWithoutExprType( - QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - unsigned IndexTypeQuals) { - return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0, - IndexTypeQuals, SourceRange()); -} - -template<typename Derived> -QualType TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, unsigned IndexTypeQuals) { @@ -4644,6 +4959,11 @@ QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T, } template<typename Derived> +QualType TreeTransform<Derived>::RebuildFunctionNoProtoType(QualType T) { + return SemaRef.Context.getFunctionNoProtoType(T); +} + +template<typename Derived> QualType TreeTransform<Derived>::RebuildTypeOfExprType(ExprArg E) { return SemaRef.BuildTypeofExprType(E.takeAs<Expr>()); } |