diff options
Diffstat (limited to 'lib')
119 files changed, 9805 insertions, 2248 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 5a91f074c4e1..fb9630180dca 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1917,11 +1917,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, // We can use protocol_iterator here instead of // all_referenced_protocol_iterator since we are walking all categories. for (auto *Proto : OI->all_referenced_protocols()) { - Protocols.insert(Proto->getCanonicalDecl()); - for (auto *P : Proto->protocols()) { - Protocols.insert(P->getCanonicalDecl()); - CollectInheritedProtocols(P, Protocols); - } + CollectInheritedProtocols(Proto, Protocols); } // Categories of this Interface. @@ -1935,16 +1931,16 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, } } else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) { for (auto *Proto : OC->protocols()) { - Protocols.insert(Proto->getCanonicalDecl()); - for (const auto *P : Proto->protocols()) - CollectInheritedProtocols(P, Protocols); + CollectInheritedProtocols(Proto, Protocols); } } else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) { - for (auto *Proto : OP->protocols()) { - Protocols.insert(Proto->getCanonicalDecl()); - for (const auto *P : Proto->protocols()) - CollectInheritedProtocols(P, Protocols); - } + // Insert the protocol. + if (!Protocols.insert( + const_cast<ObjCProtocolDecl *>(OP->getCanonicalDecl())).second) + return; + + for (auto *Proto : OP->protocols()) + CollectInheritedProtocols(Proto, Protocols); } } @@ -3618,45 +3614,89 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols, QualType ASTContext::getObjCObjectType(QualType BaseType, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) const { - // If the base type is an interface and there aren't any protocols - // to add, then the interface type will do just fine. - if (!NumProtocols && isa<ObjCInterfaceType>(BaseType)) - return BaseType; + return getObjCObjectType(BaseType, { }, + llvm::makeArrayRef(Protocols, NumProtocols), + /*isKindOf=*/false); +} + +QualType ASTContext::getObjCObjectType( + QualType baseType, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) const { + // If the base type is an interface and there aren't any protocols or + // type arguments to add, then the interface type will do just fine. + if (typeArgs.empty() && protocols.empty() && !isKindOf && + isa<ObjCInterfaceType>(baseType)) + return baseType; // Look in the folding set for an existing type. llvm::FoldingSetNodeID ID; - ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols); + ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols, isKindOf); void *InsertPos = nullptr; if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); - // Build the canonical type, which has the canonical base type and - // a sorted-and-uniqued list of protocols. - QualType Canonical; - bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols); - if (!ProtocolsSorted || !BaseType.isCanonical()) { - if (!ProtocolsSorted) { - SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, - Protocols + NumProtocols); - unsigned UniqueCount = NumProtocols; - - SortAndUniqueProtocols(&Sorted[0], UniqueCount); - Canonical = getObjCObjectType(getCanonicalType(BaseType), - &Sorted[0], UniqueCount); + // Determine the type arguments to be used for canonicalization, + // which may be explicitly specified here or written on the base + // type. + ArrayRef<QualType> effectiveTypeArgs = typeArgs; + if (effectiveTypeArgs.empty()) { + if (auto baseObject = baseType->getAs<ObjCObjectType>()) + effectiveTypeArgs = baseObject->getTypeArgs(); + } + + // Build the canonical type, which has the canonical base type and a + // sorted-and-uniqued list of protocols and the type arguments + // canonicalized. + QualType canonical; + bool typeArgsAreCanonical = std::all_of(effectiveTypeArgs.begin(), + effectiveTypeArgs.end(), + [&](QualType type) { + return type.isCanonical(); + }); + bool protocolsSorted = areSortedAndUniqued(protocols.data(), + protocols.size()); + if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) { + // Determine the canonical type arguments. + ArrayRef<QualType> canonTypeArgs; + SmallVector<QualType, 4> canonTypeArgsVec; + if (!typeArgsAreCanonical) { + canonTypeArgsVec.reserve(effectiveTypeArgs.size()); + for (auto typeArg : effectiveTypeArgs) + canonTypeArgsVec.push_back(getCanonicalType(typeArg)); + canonTypeArgs = canonTypeArgsVec; } else { - Canonical = getObjCObjectType(getCanonicalType(BaseType), - Protocols, NumProtocols); + canonTypeArgs = effectiveTypeArgs; } + ArrayRef<ObjCProtocolDecl *> canonProtocols; + SmallVector<ObjCProtocolDecl*, 8> canonProtocolsVec; + if (!protocolsSorted) { + canonProtocolsVec.insert(canonProtocolsVec.begin(), + protocols.begin(), + protocols.end()); + unsigned uniqueCount = protocols.size(); + SortAndUniqueProtocols(&canonProtocolsVec[0], uniqueCount); + canonProtocols = llvm::makeArrayRef(&canonProtocolsVec[0], uniqueCount); + } else { + canonProtocols = protocols; + } + + canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs, + canonProtocols, isKindOf); + // Regenerate InsertPos. ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos); } - unsigned Size = sizeof(ObjCObjectTypeImpl); - Size += NumProtocols * sizeof(ObjCProtocolDecl *); - void *Mem = Allocate(Size, TypeAlignment); + unsigned size = sizeof(ObjCObjectTypeImpl); + size += typeArgs.size() * sizeof(QualType); + size += protocols.size() * sizeof(ObjCProtocolDecl *); + void *mem = Allocate(size, TypeAlignment); ObjCObjectTypeImpl *T = - new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols); + new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols, + isKindOf); Types.push_back(T); ObjCObjectTypes.InsertNode(T, InsertPos); @@ -5623,13 +5663,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::ObjCInterface: { // Ignore protocol qualifiers when mangling at this level. - T = T->castAs<ObjCObjectType>()->getBaseType(); - - // The assumption seems to be that this assert will succeed - // because nested levels will have filtered out 'id' and 'Class'. - const ObjCInterfaceType *OIT = T->castAs<ObjCInterfaceType>(); // @encode(class_name) - ObjCInterfaceDecl *OI = OIT->getDecl(); + ObjCInterfaceDecl *OI = T->castAs<ObjCObjectType>()->getInterface(); S += '{'; S += OI->getObjCRuntimeNameAsString(); S += '='; @@ -5921,7 +5956,7 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, TypedefDecl *ASTContext::getObjCIdDecl() const { if (!ObjCIdDecl) { - QualType T = getObjCObjectType(ObjCBuiltinIdTy, nullptr, 0); + QualType T = getObjCObjectType(ObjCBuiltinIdTy, { }, { }); T = getObjCObjectPointerType(T); ObjCIdDecl = buildImplicitTypedef(T, "id"); } @@ -5938,7 +5973,7 @@ TypedefDecl *ASTContext::getObjCSelDecl() const { TypedefDecl *ASTContext::getObjCClassDecl() const { if (!ObjCClassDecl) { - QualType T = getObjCObjectType(ObjCBuiltinClassTy, nullptr, 0); + QualType T = getObjCObjectType(ObjCBuiltinClassTy, { }, { }); T = getObjCObjectPointerType(T); ObjCClassDecl = buildImplicitTypedef(T, "Class"); } @@ -5951,6 +5986,7 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const { = ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(), SourceLocation(), &Idents.get("Protocol"), + /*typeParamList=*/nullptr, /*PrevDecl=*/nullptr, SourceLocation(), true); } @@ -6743,18 +6779,36 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, RHS->isObjCUnqualifiedIdOrClass()) return true; - if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) - return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), - QualType(RHSOPT,0), - false); + // Function object that propagates a successful result or handles + // __kindof types. + auto finish = [&](bool succeeded) -> bool { + if (succeeded) + return true; + + if (!RHS->isKindOfType()) + return false; + + // Strip off __kindof and protocol qualifiers, then check whether + // we can assign the other way. + return canAssignObjCInterfaces(RHSOPT->stripObjCKindOfTypeAndQuals(*this), + LHSOPT->stripObjCKindOfTypeAndQuals(*this)); + }; + + if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) { + return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0), + false)); + } - if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) - return ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0), - QualType(RHSOPT,0)); + if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) { + return finish(ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0))); + } // If we have 2 user-defined types, fall into that path. - if (LHS->getInterface() && RHS->getInterface()) - return canAssignObjCInterfaces(LHS, RHS); + if (LHS->getInterface() && RHS->getInterface()) { + return finish(canAssignObjCInterfaces(LHS, RHS)); + } return false; } @@ -6768,26 +6822,46 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer( const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT, bool BlockReturnType) { + + // Function object that propagates a successful result or handles + // __kindof types. + auto finish = [&](bool succeeded) -> bool { + if (succeeded) + return true; + + const ObjCObjectPointerType *Expected = BlockReturnType ? RHSOPT : LHSOPT; + if (!Expected->isKindOfType()) + return false; + + // Strip off __kindof and protocol qualifiers, then check whether + // we can assign the other way. + return canAssignObjCInterfacesInBlockPointer( + RHSOPT->stripObjCKindOfTypeAndQuals(*this), + LHSOPT->stripObjCKindOfTypeAndQuals(*this), + BlockReturnType); + }; + if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType()) return true; if (LHSOPT->isObjCBuiltinType()) { - return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType(); + return finish(RHSOPT->isObjCBuiltinType() || + RHSOPT->isObjCQualifiedIdType()); } if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) - return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), - QualType(RHSOPT,0), - false); + return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0), + false)); const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); if (LHS && RHS) { // We have 2 user-defined types. if (LHS != RHS) { if (LHS->getDecl()->isSuperClassOf(RHS->getDecl())) - return BlockReturnType; + return finish(BlockReturnType); if (RHS->getDecl()->isSuperClassOf(LHS->getDecl())) - return !BlockReturnType; + return finish(!BlockReturnType); } else return true; @@ -6795,78 +6869,253 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer( return false; } +/// Comparison routine for Objective-C protocols to be used with +/// llvm::array_pod_sort. +static int compareObjCProtocolsByName(ObjCProtocolDecl * const *lhs, + ObjCProtocolDecl * const *rhs) { + return (*lhs)->getName().compare((*rhs)->getName()); + +} + /// getIntersectionOfProtocols - This routine finds the intersection of set -/// of protocols inherited from two distinct objective-c pointer objects. +/// of protocols inherited from two distinct objective-c pointer objects with +/// the given common base. /// It is used to build composite qualifier list of the composite type of /// the conditional expression involving two objective-c pointer objects. static void getIntersectionOfProtocols(ASTContext &Context, + const ObjCInterfaceDecl *CommonBase, const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT, - SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) { + SmallVectorImpl<ObjCProtocolDecl *> &IntersectionSet) { const ObjCObjectType* LHS = LHSOPT->getObjectType(); const ObjCObjectType* RHS = RHSOPT->getObjectType(); assert(LHS->getInterface() && "LHS must have an interface base"); assert(RHS->getInterface() && "RHS must have an interface base"); - - llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet; - unsigned LHSNumProtocols = LHS->getNumProtocols(); - if (LHSNumProtocols > 0) - InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end()); - else { - llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols; - Context.CollectInheritedProtocols(LHS->getInterface(), - LHSInheritedProtocols); - InheritedProtocolSet.insert(LHSInheritedProtocols.begin(), - LHSInheritedProtocols.end()); + + // Add all of the protocols for the LHS. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSProtocolSet; + + // Start with the protocol qualifiers. + for (auto proto : LHS->quals()) { + Context.CollectInheritedProtocols(proto, LHSProtocolSet); } - - unsigned RHSNumProtocols = RHS->getNumProtocols(); - if (RHSNumProtocols > 0) { - ObjCProtocolDecl **RHSProtocols = - const_cast<ObjCProtocolDecl **>(RHS->qual_begin()); - for (unsigned i = 0; i < RHSNumProtocols; ++i) - if (InheritedProtocolSet.count(RHSProtocols[i])) - IntersectionOfProtocols.push_back(RHSProtocols[i]); - } else { - llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols; - Context.CollectInheritedProtocols(RHS->getInterface(), - RHSInheritedProtocols); - for (ObjCProtocolDecl *ProtDecl : RHSInheritedProtocols) - if (InheritedProtocolSet.count(ProtDecl)) - IntersectionOfProtocols.push_back(ProtDecl); + + // Also add the protocols associated with the LHS interface. + Context.CollectInheritedProtocols(LHS->getInterface(), LHSProtocolSet); + + // Add all of the protocls for the RHS. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSProtocolSet; + + // Start with the protocol qualifiers. + for (auto proto : RHS->quals()) { + Context.CollectInheritedProtocols(proto, RHSProtocolSet); + } + + // Also add the protocols associated with the RHS interface. + Context.CollectInheritedProtocols(RHS->getInterface(), RHSProtocolSet); + + // Compute the intersection of the collected protocol sets. + for (auto proto : LHSProtocolSet) { + if (RHSProtocolSet.count(proto)) + IntersectionSet.push_back(proto); } + + // Compute the set of protocols that is implied by either the common type or + // the protocols within the intersection. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ImpliedProtocols; + Context.CollectInheritedProtocols(CommonBase, ImpliedProtocols); + + // Remove any implied protocols from the list of inherited protocols. + if (!ImpliedProtocols.empty()) { + IntersectionSet.erase( + std::remove_if(IntersectionSet.begin(), + IntersectionSet.end(), + [&](ObjCProtocolDecl *proto) -> bool { + return ImpliedProtocols.count(proto) > 0; + }), + IntersectionSet.end()); + } + + // Sort the remaining protocols by name. + llvm::array_pod_sort(IntersectionSet.begin(), IntersectionSet.end(), + compareObjCProtocolsByName); +} + +/// Determine whether the first type is a subtype of the second. +static bool canAssignObjCObjectTypes(ASTContext &ctx, QualType lhs, + QualType rhs) { + // Common case: two object pointers. + const ObjCObjectPointerType *lhsOPT = lhs->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); + if (lhsOPT && rhsOPT) + return ctx.canAssignObjCInterfaces(lhsOPT, rhsOPT); + + // Two block pointers. + const BlockPointerType *lhsBlock = lhs->getAs<BlockPointerType>(); + const BlockPointerType *rhsBlock = rhs->getAs<BlockPointerType>(); + if (lhsBlock && rhsBlock) + return ctx.typesAreBlockPointerCompatible(lhs, rhs); + + // If either is an unqualified 'id' and the other is a block, it's + // acceptable. + if ((lhsOPT && lhsOPT->isObjCIdType() && rhsBlock) || + (rhsOPT && rhsOPT->isObjCIdType() && lhsBlock)) + return true; + + return false; +} + +// Check that the given Objective-C type argument lists are equivalent. +static bool sameObjCTypeArgs(ASTContext &ctx, + const ObjCInterfaceDecl *iface, + ArrayRef<QualType> lhsArgs, + ArrayRef<QualType> rhsArgs, + bool stripKindOf) { + if (lhsArgs.size() != rhsArgs.size()) + return false; + + ObjCTypeParamList *typeParams = iface->getTypeParamList(); + for (unsigned i = 0, n = lhsArgs.size(); i != n; ++i) { + if (ctx.hasSameType(lhsArgs[i], rhsArgs[i])) + continue; + + switch (typeParams->begin()[i]->getVariance()) { + case ObjCTypeParamVariance::Invariant: + if (!stripKindOf || + !ctx.hasSameType(lhsArgs[i].stripObjCKindOfType(ctx), + rhsArgs[i].stripObjCKindOfType(ctx))) { + return false; + } + break; + + case ObjCTypeParamVariance::Covariant: + if (!canAssignObjCObjectTypes(ctx, lhsArgs[i], rhsArgs[i])) + return false; + break; + + case ObjCTypeParamVariance::Contravariant: + if (!canAssignObjCObjectTypes(ctx, rhsArgs[i], lhsArgs[i])) + return false; + break; + } + } + + return true; } -/// areCommonBaseCompatible - Returns common base class of the two classes if -/// one found. Note that this is O'2 algorithm. But it will be called as the -/// last type comparison in a ?-exp of ObjC pointer types before a -/// warning is issued. So, its invokation is extremely rare. QualType ASTContext::areCommonBaseCompatible( - const ObjCObjectPointerType *Lptr, - const ObjCObjectPointerType *Rptr) { + const ObjCObjectPointerType *Lptr, + const ObjCObjectPointerType *Rptr) { const ObjCObjectType *LHS = Lptr->getObjectType(); const ObjCObjectType *RHS = Rptr->getObjectType(); const ObjCInterfaceDecl* LDecl = LHS->getInterface(); const ObjCInterfaceDecl* RDecl = RHS->getInterface(); - if (!LDecl || !RDecl || (declaresSameEntity(LDecl, RDecl))) + + if (!LDecl || !RDecl) return QualType(); - - do { - LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl)); - if (canAssignObjCInterfaces(LHS, RHS)) { + + // Follow the left-hand side up the class hierarchy until we either hit a + // root or find the RHS. Record the ancestors in case we don't find it. + llvm::SmallDenseMap<const ObjCInterfaceDecl *, const ObjCObjectType *, 4> + LHSAncestors; + while (true) { + // Record this ancestor. We'll need this if the common type isn't in the + // path from the LHS to the root. + LHSAncestors[LHS->getInterface()->getCanonicalDecl()] = LHS; + + if (declaresSameEntity(LHS->getInterface(), RDecl)) { + // Get the type arguments. + ArrayRef<QualType> LHSTypeArgs = LHS->getTypeArgsAsWritten(); + bool anyChanges = false; + if (LHS->isSpecialized() && RHS->isSpecialized()) { + // Both have type arguments, compare them. + if (!sameObjCTypeArgs(*this, LHS->getInterface(), + LHS->getTypeArgs(), RHS->getTypeArgs(), + /*stripKindOf=*/true)) + return QualType(); + } else if (LHS->isSpecialized() != RHS->isSpecialized()) { + // If only one has type arguments, the result will not have type + // arguments. + LHSTypeArgs = { }; + anyChanges = true; + } + + // Compute the intersection of protocols. SmallVector<ObjCProtocolDecl *, 8> Protocols; - getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols); + getIntersectionOfProtocols(*this, LHS->getInterface(), Lptr, Rptr, + Protocols); + if (!Protocols.empty()) + anyChanges = true; + + // If anything in the LHS will have changed, build a new result type. + if (anyChanges) { + QualType Result = getObjCInterfaceType(LHS->getInterface()); + Result = getObjCObjectType(Result, LHSTypeArgs, Protocols, + LHS->isKindOfType()); + return getObjCObjectPointerType(Result); + } + + return getObjCObjectPointerType(QualType(LHS, 0)); + } + + // Find the superclass. + QualType LHSSuperType = LHS->getSuperClassType(); + if (LHSSuperType.isNull()) + break; - QualType Result = QualType(LHS, 0); + LHS = LHSSuperType->castAs<ObjCObjectType>(); + } + + // We didn't find anything by following the LHS to its root; now check + // the RHS against the cached set of ancestors. + while (true) { + auto KnownLHS = LHSAncestors.find(RHS->getInterface()->getCanonicalDecl()); + if (KnownLHS != LHSAncestors.end()) { + LHS = KnownLHS->second; + + // Get the type arguments. + ArrayRef<QualType> RHSTypeArgs = RHS->getTypeArgsAsWritten(); + bool anyChanges = false; + if (LHS->isSpecialized() && RHS->isSpecialized()) { + // Both have type arguments, compare them. + if (!sameObjCTypeArgs(*this, LHS->getInterface(), + LHS->getTypeArgs(), RHS->getTypeArgs(), + /*stripKindOf=*/true)) + return QualType(); + } else if (LHS->isSpecialized() != RHS->isSpecialized()) { + // If only one has type arguments, the result will not have type + // arguments. + RHSTypeArgs = { }; + anyChanges = true; + } + + // Compute the intersection of protocols. + SmallVector<ObjCProtocolDecl *, 8> Protocols; + getIntersectionOfProtocols(*this, RHS->getInterface(), Lptr, Rptr, + Protocols); if (!Protocols.empty()) - Result = getObjCObjectType(Result, Protocols.data(), Protocols.size()); - Result = getObjCObjectPointerType(Result); - return Result; + anyChanges = true; + + if (anyChanges) { + QualType Result = getObjCInterfaceType(RHS->getInterface()); + Result = getObjCObjectType(Result, RHSTypeArgs, Protocols, + RHS->isKindOfType()); + return getObjCObjectPointerType(Result); + } + + return getObjCObjectPointerType(QualType(RHS, 0)); } - } while ((LDecl = LDecl->getSuperClass())); - + + // Find the superclass of the RHS. + QualType RHSSuperType = RHS->getSuperClassType(); + if (RHSSuperType.isNull()) + break; + + RHS = RHSSuperType->castAs<ObjCObjectType>(); + } + return QualType(); } @@ -6877,21 +7126,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, // Verify that the base decls are compatible: the RHS must be a subclass of // the LHS. - if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface())) + ObjCInterfaceDecl *LHSInterface = LHS->getInterface(); + bool IsSuperClass = LHSInterface->isSuperClassOf(RHS->getInterface()); + if (!IsSuperClass) return false; - // RHS must have a superset of the protocols in the LHS. If the LHS is not - // protocol qualified at all, then we are good. - if (LHS->getNumProtocols() == 0) - return true; - - // Okay, we know the LHS has protocol qualifiers. But RHS may or may not. - // More detailed analysis is required. - // OK, if LHS is same or a superclass of RHS *and* - // this LHS, or as RHS's super class is assignment compatible with LHS. - bool IsSuperClass = - LHS->getInterface()->isSuperClassOf(RHS->getInterface()); - if (IsSuperClass) { + // If the LHS has protocol qualifiers, determine whether all of them are + // satisfied by the RHS (i.e., the RHS has a superset of the protocols in the + // LHS). + if (LHS->getNumProtocols() > 0) { // OK if conversion of LHS to SuperClass results in narrowing of types // ; i.e., SuperClass may implement at least one of the protocols // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok. @@ -6901,7 +7144,7 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, // Also, if RHS has explicit quelifiers, include them for comparing with LHS's // qualifiers. for (auto *RHSPI : RHS->quals()) - SuperClassInheritedProtocols.insert(RHSPI->getCanonicalDecl()); + CollectInheritedProtocols(RHSPI, SuperClassInheritedProtocols); // If there is no protocols associated with RHS, it is not a match. if (SuperClassInheritedProtocols.empty()) return false; @@ -6916,9 +7159,26 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, if (!SuperImplementsProtocol) return false; } - return true; } - return false; + + // If the LHS is specialized, we may need to check type arguments. + if (LHS->isSpecialized()) { + // Follow the superclass chain until we've matched the LHS class in the + // hierarchy. This substitutes type arguments through. + const ObjCObjectType *RHSSuper = RHS; + while (!declaresSameEntity(RHSSuper->getInterface(), LHSInterface)) + RHSSuper = RHSSuper->getSuperClassType()->castAs<ObjCObjectType>(); + + // If the RHS is specializd, compare type arguments. + if (RHSSuper->isSpecialized() && + !sameObjCTypeArgs(*this, LHS->getInterface(), + LHS->getTypeArgs(), RHSSuper->getTypeArgs(), + /*stripKindOf=*/true)) { + return false; + } + } + + return true; } bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 000588face96..dddaa5af6fb0 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -125,12 +125,23 @@ break; \ if (const PointerType *Ty = QT->getAs<PointerType>()) { QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); + } else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) { + QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) { QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); + } else if (const auto *Ty = QT->getAs<ObjCObjectType>()) { + if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) { + QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA); + QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(), + llvm::makeArrayRef(Ty->qual_begin(), + Ty->getNumProtocols()), + Ty->isKindOfTypeAsWritten()); + } } return QC.apply(Context, QT); @@ -181,8 +192,8 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, if (CompareCanTy == CanTy) continue; // Same canonical types std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy()); - bool aka; - QualType CompareDesugar = Desugar(Context, CompareTy, aka); + bool ShouldAKA = false; + QualType CompareDesugar = Desugar(Context, CompareTy, ShouldAKA); std::string CompareDesugarStr = CompareDesugar.getAsString(Context.getPrintingPolicy()); if (CompareS != S && CompareDesugarStr != S) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 90da4167197a..c95922b141e0 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -240,6 +240,9 @@ namespace { void dumpTemplateArgument(const TemplateArgument &A, SourceRange R = SourceRange()); + // Objective-C utilities. + void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams); + // Types void VisitComplexType(const ComplexType *T) { dumpTypeAsChild(T->getElementType()); @@ -463,6 +466,7 @@ namespace { // ObjC Decls void VisitObjCIvarDecl(const ObjCIvarDecl *D); void VisitObjCMethodDecl(const ObjCMethodDecl *D); + void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D); void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); @@ -955,6 +959,18 @@ void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) { } //===----------------------------------------------------------------------===// +// Objective-C Utilities +//===----------------------------------------------------------------------===// +void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) { + if (!typeParams) + return; + + for (auto typeParam : *typeParams) { + dumpDecl(typeParam); + } +} + +//===----------------------------------------------------------------------===// // Decl dumping methods. //===----------------------------------------------------------------------===// @@ -1457,9 +1473,30 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { dumpStmt(D->getBody()); } +void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) { + dumpName(D); + switch (D->getVariance()) { + case ObjCTypeParamVariance::Invariant: + break; + + case ObjCTypeParamVariance::Covariant: + OS << " covariant"; + break; + + case ObjCTypeParamVariance::Contravariant: + OS << " contravariant"; + break; + } + + if (D->hasExplicitBound()) + OS << " bounded"; + dumpType(D->getUnderlyingType()); +} + void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { dumpName(D); dumpDeclRef(D->getClassInterface()); + dumpObjCTypeParamList(D->getTypeParamList()); dumpDeclRef(D->getImplementation()); for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); @@ -1482,6 +1519,7 @@ void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { dumpName(D); + dumpObjCTypeParamList(D->getTypeParamListAsWritten()); dumpDeclRef(D->getSuperClass(), "super"); dumpDeclRef(D->getImplementation()); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 76e4e1191501..35c0f690db82 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -150,9 +150,12 @@ namespace clang { Decl *VisitImplicitParamDecl(ImplicitParamDecl *D); Decl *VisitParmVarDecl(ParmVarDecl *D); Decl *VisitObjCMethodDecl(ObjCMethodDecl *D); + Decl *VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D); Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D); Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D); + + ObjCTypeParamList *ImportObjCTypeParamList(ObjCTypeParamList *list); Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D); @@ -1841,6 +1844,15 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { if (ToBaseType.isNull()) return QualType(); + SmallVector<QualType, 4> TypeArgs; + for (auto TypeArg : T->getTypeArgsAsWritten()) { + QualType ImportedTypeArg = Importer.Import(TypeArg); + if (ImportedTypeArg.isNull()) + return QualType(); + + TypeArgs.push_back(ImportedTypeArg); + } + SmallVector<ObjCProtocolDecl *, 4> Protocols; for (auto *P : T->quals()) { ObjCProtocolDecl *Protocol @@ -1850,9 +1862,9 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { Protocols.push_back(Protocol); } - return Importer.getToContext().getObjCObjectType(ToBaseType, - Protocols.data(), - Protocols.size()); + return Importer.getToContext().getObjCObjectType(ToBaseType, TypeArgs, + Protocols, + T->isKindOfTypeAsWritten()); } QualType @@ -3423,6 +3435,35 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { return ToMethod; } +Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { + // Import the major distinguishing characteristics of a category. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + if (ToD) + return ToD; + + TypeSourceInfo *BoundInfo = Importer.Import(D->getTypeSourceInfo()); + if (!BoundInfo) + return nullptr; + + ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create( + Importer.getToContext(), DC, + D->getVariance(), + Importer.Import(D->getVarianceLoc()), + D->getIndex(), + Importer.Import(D->getLocation()), + Name.getAsIdentifierInfo(), + Importer.Import(D->getColonLoc()), + BoundInfo); + Importer.Imported(D, Result); + Result->setLexicalDeclContext(LexicalDC); + return Result; +} + Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { // Import the major distinguishing characteristics of a category. DeclContext *DC, *LexicalDC; @@ -3450,11 +3491,16 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { Importer.Import(D->getCategoryNameLoc()), Name.getAsIdentifierInfo(), ToInterface, + /*TypeParamList=*/nullptr, Importer.Import(D->getIvarLBraceLoc()), Importer.Import(D->getIvarRBraceLoc())); ToCategory->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToCategory); Importer.Imported(D, ToCategory); + // Import the type parameter list after calling Imported, to avoid + // loops when bringing in their DeclContext. + ToCategory->setTypeParamList(ImportObjCTypeParamList( + D->getTypeParamList())); // Import protocols SmallVector<ObjCProtocolDecl *, 4> Protocols; @@ -3663,13 +3709,11 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, // If this class has a superclass, import it. if (From->getSuperClass()) { - ObjCInterfaceDecl *Super = cast_or_null<ObjCInterfaceDecl>( - Importer.Import(From->getSuperClass())); - if (!Super) + TypeSourceInfo *SuperTInfo = Importer.Import(From->getSuperClassTInfo()); + if (!SuperTInfo) return true; - - To->setSuperClass(Super); - To->setSuperClassLoc(Importer.Import(From->getSuperClassLoc())); + + To->setSuperClass(SuperTInfo); } // Import protocols @@ -3716,6 +3760,27 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, return false; } +ObjCTypeParamList * +ASTNodeImporter::ImportObjCTypeParamList(ObjCTypeParamList *list) { + if (!list) + return nullptr; + + SmallVector<ObjCTypeParamDecl *, 4> toTypeParams; + for (auto fromTypeParam : *list) { + auto toTypeParam = cast_or_null<ObjCTypeParamDecl>( + Importer.Import(fromTypeParam)); + if (!toTypeParam) + return nullptr; + + toTypeParams.push_back(toTypeParam); + } + + return ObjCTypeParamList::create(Importer.getToContext(), + Importer.Import(list->getLAngleLoc()), + toTypeParams, + Importer.Import(list->getRAngleLoc())); +} + Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // If this class has a definition in the translation unit we're coming from, // but this particular declaration is not that definition, import the @@ -3756,13 +3821,18 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { if (!ToIface) { ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC, Importer.Import(D->getAtStartLoc()), - Name.getAsIdentifierInfo(), + Name.getAsIdentifierInfo(), + /*TypeParamList=*/nullptr, /*PrevDecl=*/nullptr, Loc, D->isImplicitInterfaceDecl()); ToIface->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToIface); } Importer.Imported(D, ToIface); + // Import the type parameter list after calling Imported, to avoid + // loops when bringing in their DeclContext. + ToIface->setTypeParamList(ImportObjCTypeParamList( + D->getTypeParamListAsWritten())); if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToIface)) return nullptr; @@ -5313,7 +5383,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { return nullptr; return ToContext.getTrivialTypeSourceInfo(T, - FromTSI->getTypeLoc().getLocStart()); + Import(FromTSI->getTypeLoc().getLocStart())); } Decl *ASTImporter::GetAlreadyImportedOrNull(Decl *FromD) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d9a3389c58f3..ea4b2f517cd0 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1803,15 +1803,19 @@ void VarDecl::setStorageClass(StorageClass SC) { VarDecl::TLSKind VarDecl::getTLSKind() const { switch (VarDeclBits.TSCSpec) { case TSCS_unspecified: - if (!hasAttr<ThreadAttr>()) + if (!hasAttr<ThreadAttr>() && + !(getASTContext().getLangOpts().OpenMPUseTLS && + getASTContext().getTargetInfo().isTLSSupported() && + hasAttr<OMPThreadPrivateDeclAttr>())) return TLS_None; - return getASTContext().getLangOpts().isCompatibleWithMSVC( - LangOptions::MSVC2015) + return ((getASTContext().getLangOpts().isCompatibleWithMSVC( + LangOptions::MSVC2015)) || + hasAttr<OMPThreadPrivateDeclAttr>()) ? TLS_Dynamic : TLS_Static; case TSCS___thread: // Fall through. case TSCS__Thread_local: - return TLS_Static; + return TLS_Static; case TSCS_thread_local: return TLS_Dynamic; } @@ -2712,7 +2716,7 @@ bool FunctionDecl::isMSExternInline() const { for (const FunctionDecl *FD = getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) - if (FD->getStorageClass() == SC_Extern) + if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern) return true; return false; @@ -2724,7 +2728,7 @@ static bool redeclForcesDefMSVC(const FunctionDecl *Redecl) { for (const FunctionDecl *FD = Redecl->getPreviousDecl(); FD; FD = FD->getPreviousDecl()) - if (FD->getStorageClass() == SC_Extern) + if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern) return false; return true; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index d20451d1badc..4fcec53d6eb9 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -561,6 +561,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case TypeAliasTemplate: case UnresolvedUsingTypename: case TemplateTypeParm: + case ObjCTypeParam: return IDNS_Ordinary | IDNS_Type; case UsingShadow: diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index b00b8a0ea9cc..d905fcf13a45 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1272,7 +1272,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { break; CTD = NewCTD; } - return CTD->getTemplatedDecl(); + return CTD->getTemplatedDecl()->getDefinition(); } if (auto *CTPSD = From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) { @@ -1281,7 +1281,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { break; CTPSD = NewCTPSD; } - return CTPSD; + return CTPSD->getDefinition(); } } @@ -1290,7 +1290,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { const CXXRecordDecl *RD = this; while (auto *NewRD = RD->getInstantiatedFromMemberClass()) RD = NewRD; - return RD; + return RD->getDefinition(); } } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index a1600cb11014..280c412ae8ff 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -239,6 +239,62 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( void ObjCInterfaceDecl::anchor() { } +ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const { + // If this particular declaration has a type parameter list, return it. + if (ObjCTypeParamList *written = getTypeParamListAsWritten()) + return written; + + // If there is a definition, return its type parameter list. + if (const ObjCInterfaceDecl *def = getDefinition()) + return def->getTypeParamListAsWritten(); + + // Otherwise, look at previous declarations to determine whether any + // of them has a type parameter list, skipping over those + // declarations that do not. + for (auto decl = getMostRecentDecl(); decl; decl = decl->getPreviousDecl()) { + if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten()) + return written; + } + + return nullptr; +} + +void ObjCInterfaceDecl::setTypeParamList(ObjCTypeParamList *TPL) { + TypeParamList = TPL; + if (!TPL) + return; + // Set the declaration context of each of the type parameters. + for (auto typeParam : *TypeParamList) + typeParam->setDeclContext(this); +} + +ObjCInterfaceDecl *ObjCInterfaceDecl::getSuperClass() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return nullptr; + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + if (const ObjCObjectType *superType = getSuperClassType()) { + if (ObjCInterfaceDecl *superDecl = superType->getInterface()) { + if (ObjCInterfaceDecl *superDef = superDecl->getDefinition()) + return superDef; + + return superDecl; + } + } + + return nullptr; +} + +SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const { + if (TypeSourceInfo *superTInfo = getSuperClassTInfo()) + return superTInfo->getTypeLoc().getLocStart(); + + return SourceLocation(); +} + /// FindPropertyVisibleInPrimaryClass - Finds declaration of the property /// with name 'PropertyId' in the primary class; including those in protocols /// (direct or indirect) used by the primary class. @@ -889,9 +945,13 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { return family; } -void ObjCMethodDecl::createImplicitParams(ASTContext &Context, - const ObjCInterfaceDecl *OID) { +QualType ObjCMethodDecl::getSelfType(ASTContext &Context, + const ObjCInterfaceDecl *OID, + bool &selfIsPseudoStrong, + bool &selfIsConsumed) { QualType selfTy; + selfIsPseudoStrong = false; + selfIsConsumed = false; if (isInstanceMethod()) { // There may be no interface context due to error in declaration // of the interface (which has been reported). Recover gracefully. @@ -904,9 +964,6 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, } else // we have a factory method. selfTy = Context.getObjCClassType(); - bool selfIsPseudoStrong = false; - bool selfIsConsumed = false; - if (Context.getLangOpts().ObjCAutoRefCount) { if (isInstanceMethod()) { selfIsConsumed = hasAttr<NSConsumesSelfAttr>(); @@ -930,7 +987,14 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, selfIsPseudoStrong = true; } } + return selfTy; +} +void ObjCMethodDecl::createImplicitParams(ASTContext &Context, + const ObjCInterfaceDecl *OID) { + bool selfIsPseudoStrong, selfIsConsumed; + QualType selfTy = + getSelfType(Context, OID, selfIsPseudoStrong, selfIsConsumed); ImplicitParamDecl *self = ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("self"), selfTy); @@ -966,6 +1030,20 @@ SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const { return SourceRange(); } +QualType ObjCMethodDecl::getSendResultType() const { + ASTContext &Ctx = getASTContext(); + return getReturnType().getNonLValueExprType(Ctx) + .substObjCTypeArgs(Ctx, {}, ObjCSubstitutionContext::Result); +} + +QualType ObjCMethodDecl::getSendResultType(QualType receiverType) const { + // FIXME: Handle related result types here. + + return getReturnType().getNonLValueExprType(getASTContext()) + .substObjCMemberType(receiverType, getDeclContext(), + ObjCSubstitutionContext::Result); +} + static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, const ObjCMethodDecl *Method, SmallVectorImpl<const ObjCMethodDecl *> &Methods, @@ -1137,6 +1215,81 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { } //===----------------------------------------------------------------------===// +// ObjCTypeParamDecl +//===----------------------------------------------------------------------===// + +void ObjCTypeParamDecl::anchor() { } + +ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc, + ObjCTypeParamVariance variance, + SourceLocation varianceLoc, + unsigned index, + SourceLocation nameLoc, + IdentifierInfo *name, + SourceLocation colonLoc, + TypeSourceInfo *boundInfo) { + return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index, + nameLoc, name, colonLoc, boundInfo); +} + +ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx, + unsigned ID) { + return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, + ObjCTypeParamVariance::Invariant, + SourceLocation(), 0, SourceLocation(), + nullptr, SourceLocation(), nullptr); +} + +SourceRange ObjCTypeParamDecl::getSourceRange() const { + SourceLocation startLoc = VarianceLoc; + if (startLoc.isInvalid()) + startLoc = getLocation(); + + if (hasExplicitBound()) { + return SourceRange(startLoc, + getTypeSourceInfo()->getTypeLoc().getEndLoc()); + } + + return SourceRange(startLoc); +} + +//===----------------------------------------------------------------------===// +// ObjCTypeParamList +//===----------------------------------------------------------------------===// +ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc, + ArrayRef<ObjCTypeParamDecl *> typeParams, + SourceLocation rAngleLoc) + : NumParams(typeParams.size()) +{ + Brackets.Begin = lAngleLoc.getRawEncoding(); + Brackets.End = rAngleLoc.getRawEncoding(); + std::copy(typeParams.begin(), typeParams.end(), begin()); +} + + +ObjCTypeParamList *ObjCTypeParamList::create( + ASTContext &ctx, + SourceLocation lAngleLoc, + ArrayRef<ObjCTypeParamDecl *> typeParams, + SourceLocation rAngleLoc) { + unsigned size = sizeof(ObjCTypeParamList) + + sizeof(ObjCTypeParamDecl *) * typeParams.size(); + static_assert(llvm::AlignOf<ObjCTypeParamList>::Alignment >= + llvm::AlignOf<ObjCTypeParamDecl *>::Alignment, + "type parameter list needs greater alignment"); + unsigned align = llvm::alignOf<ObjCTypeParamList>(); + void *mem = ctx.Allocate(size, align); + return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc); +} + +void ObjCTypeParamList::gatherDefaultTypeArgs( + SmallVectorImpl<QualType> &typeArgs) const { + typeArgs.reserve(size()); + for (auto typeParam : *this) + typeArgs.push_back(typeParam->getUnderlyingType()); +} + +//===----------------------------------------------------------------------===// // ObjCInterfaceDecl //===----------------------------------------------------------------------===// @@ -1144,11 +1297,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, + ObjCTypeParamList *typeParamList, ObjCInterfaceDecl *PrevDecl, SourceLocation ClassLoc, bool isInternal){ ObjCInterfaceDecl *Result = new (C, DC) - ObjCInterfaceDecl(C, DC, atLoc, Id, ClassLoc, PrevDecl, isInternal); + ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl, + isInternal); Result->Data.setInt(!C.getLangOpts().Modules); C.getObjCInterfaceType(Result, PrevDecl); return Result; @@ -1159,6 +1314,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C, ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr, SourceLocation(), nullptr, + nullptr, SourceLocation(), nullptr, false); Result->Data.setInt(!C.getLangOpts().Modules); @@ -1167,11 +1323,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C, ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, IdentifierInfo *Id, + ObjCTypeParamList *typeParamList, SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, bool IsInternal) : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc), - redeclarable_base(C), TypeForDecl(nullptr), Data() { + redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(nullptr), + Data() { setPreviousDecl(PrevDecl); // Copy the 'data' pointer over. @@ -1179,6 +1337,8 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, Data = PrevDecl->Data; setImplicit(IsInternal); + + setTypeParamList(typeParamList); } void ObjCInterfaceDecl::LoadExternalDefinition() const { @@ -1492,6 +1652,11 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { } } +QualType ObjCIvarDecl::getUsageType(QualType objectType) const { + return getType().substObjCMemberType(objectType, getDeclContext(), + ObjCSubstitutionContext::Property); +} + //===----------------------------------------------------------------------===// // ObjCAtDefsFieldDecl //===----------------------------------------------------------------------===// @@ -1648,17 +1813,34 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const { void ObjCCategoryDecl::anchor() { } +ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, + SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, + IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, + SourceLocation IvarLBraceLoc, + SourceLocation IvarRBraceLoc) + : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc), + ClassInterface(IDecl), TypeParamList(nullptr), + NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc), + IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) +{ + setTypeParamList(typeParamList); +} + ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc, SourceLocation IvarRBraceLoc) { ObjCCategoryDecl *CatDecl = new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id, - IDecl, IvarLBraceLoc, IvarRBraceLoc); + IDecl, typeParamList, IvarLBraceLoc, + IvarRBraceLoc); if (IDecl) { // Link this category into its class's category list. CatDecl->NextClassCategory = IDecl->getCategoryListRaw(); @@ -1676,7 +1858,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(), SourceLocation(), SourceLocation(), - nullptr, nullptr); + nullptr, nullptr, nullptr); } ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const { @@ -1688,6 +1870,15 @@ void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) { getASTContext().setObjCImplementation(this, ImplD); } +void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) { + TypeParamList = TPL; + if (!TPL) + return; + // Set the declaration context of each of the type parameters. + for (auto typeParam : *TypeParamList) + typeParam->setDeclContext(this); +} + //===----------------------------------------------------------------------===// // ObjCCategoryImplDecl @@ -1876,6 +2067,11 @@ ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C, QualType(), nullptr, None); } +QualType ObjCPropertyDecl::getUsageType(QualType objectType) const { + return DeclType.substObjCMemberType(objectType, getDeclContext(), + ObjCSubstitutionContext::Property); +} + //===----------------------------------------------------------------------===// // ObjCPropertyImplDecl //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index d33093b8b5e1..3202d8c75436 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -44,6 +44,8 @@ namespace { void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals, QualType T); + void PrintObjCTypeParams(ObjCTypeParamList *Params); + public: DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0, bool PrintInstantiation = false) @@ -962,6 +964,38 @@ void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx, Out << ')'; } +void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) { + Out << "<"; + unsigned First = true; + for (auto *Param : *Params) { + if (First) { + First = false; + } else { + Out << ", "; + } + + switch (Param->getVariance()) { + case ObjCTypeParamVariance::Invariant: + break; + + case ObjCTypeParamVariance::Covariant: + Out << "__covariant "; + break; + + case ObjCTypeParamVariance::Contravariant: + Out << "__contravariant "; + break; + } + + Out << Param->getDeclName().getAsString(); + + if (Param->hasExplicitBound()) { + Out << " : " << Param->getUnderlyingType().getAsString(Policy); + } + } + Out << ">"; +} + void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { if (OMD->isInstanceMethod()) Out << "- "; @@ -1037,14 +1071,24 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (!OID->isThisDeclarationADefinition()) { - Out << "@class " << I << ";"; + Out << "@class " << I; + + if (auto TypeParams = OID->getTypeParamListAsWritten()) { + PrintObjCTypeParams(TypeParams); + } + + Out << ";"; return; } bool eolnOut = false; + Out << "@interface " << I; + + if (auto TypeParams = OID->getTypeParamListAsWritten()) { + PrintObjCTypeParams(TypeParams); + } + if (SID) - Out << "@interface " << I << " : " << *SID; - else - Out << "@interface " << I; + Out << " : " << OID->getSuperClass()->getName(); // Protocols? const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols(); @@ -1107,7 +1151,11 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { } void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { - Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n"; + Out << "@interface " << *PID->getClassInterface(); + if (auto TypeParams = PID->getTypeParamList()) { + PrintObjCTypeParams(TypeParams); + } + Out << "(" << *PID << ")\n"; if (PID->ivar_size() > 0) { Out << "{\n"; Indentation += Policy.Indentation; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 87f9ffba78e3..2e066b2c42c6 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -3748,6 +3748,16 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { return nullptr; } +QualType ObjCPropertyRefExpr::getReceiverType(const ASTContext &ctx) const { + if (isClassReceiver()) + return ctx.getObjCInterfaceType(getClassReceiver()); + + if (isSuperReceiver()) + return getSuperReceiverType(); + + return getBase()->getType(); +} + StringRef ObjCBridgedCastExpr::getBridgeKindName() const { switch (getBridgeKind()) { case OBC_Bridge: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 0134c090d67e..dac803e5d2ff 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2379,6 +2379,10 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { } void CXXNameMangler::mangleType(const ObjCObjectType *T) { + // Treat __kindof as a vendor extended type qualifier. + if (T->isKindOfType()) + Out << "U8__kindof"; + if (!T->qual_empty()) { // Mangle protocol qualifiers. SmallString<64> QualStr; @@ -2391,7 +2395,16 @@ void CXXNameMangler::mangleType(const ObjCObjectType *T) { QualOS.flush(); Out << 'U' << QualStr.size() << QualStr; } + mangleType(T->getBaseType()); + + if (T->isSpecialized()) { + // Mangle type arguments as I <type>+ E + Out << 'I'; + for (auto typeArg : T->getTypeArgs()) + mangleType(typeArg); + Out << 'E'; + } } void CXXNameMangler::mangleType(const BlockPointerType *T) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 541bd1ebdf88..cee5fee83913 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -466,18 +466,976 @@ const RecordType *Type::getAsUnionType() const { return nullptr; } +bool Type::isObjCIdOrObjectKindOfType(const ASTContext &ctx, + const ObjCObjectType *&bound) const { + bound = nullptr; + + const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>(); + if (!OPT) + return false; + + // Easy case: id. + if (OPT->isObjCIdType()) + return true; + + // If it's not a __kindof type, reject it now. + if (!OPT->isKindOfType()) + return false; + + // If it's Class or qualified Class, it's not an object type. + if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) + return false; + + // Figure out the type bound for the __kindof type. + bound = OPT->getObjectType()->stripObjCKindOfTypeAndQuals(ctx) + ->getAs<ObjCObjectType>(); + return true; +} + +bool Type::isObjCClassOrClassKindOfType() const { + const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>(); + if (!OPT) + return false; + + // Easy case: Class. + if (OPT->isObjCClassType()) + return true; + + // If it's not a __kindof type, reject it now. + if (!OPT->isKindOfType()) + return false; + + // If it's Class or qualified Class, it's a class __kindof type. + return OPT->isObjCClassType() || OPT->isObjCQualifiedClassType(); +} + ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, - ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) - : Type(ObjCObject, Canonical, false, false, false, false), + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) + : Type(ObjCObject, Canonical, Base->isDependentType(), + Base->isInstantiationDependentType(), + Base->isVariablyModifiedType(), + Base->containsUnexpandedParameterPack()), BaseType(Base) { - ObjCObjectTypeBits.NumProtocols = NumProtocols; - assert(getNumProtocols() == NumProtocols && + ObjCObjectTypeBits.IsKindOf = isKindOf; + + ObjCObjectTypeBits.NumTypeArgs = typeArgs.size(); + assert(getTypeArgsAsWritten().size() == typeArgs.size() && + "bitfield overflow in type argument count"); + ObjCObjectTypeBits.NumProtocols = protocols.size(); + assert(getNumProtocols() == protocols.size() && "bitfield overflow in protocol count"); - if (NumProtocols) - memcpy(getProtocolStorage(), Protocols, - NumProtocols * sizeof(ObjCProtocolDecl*)); + if (!typeArgs.empty()) + memcpy(getTypeArgStorage(), typeArgs.data(), + typeArgs.size() * sizeof(QualType)); + if (!protocols.empty()) + memcpy(getProtocolStorage(), protocols.data(), + protocols.size() * sizeof(ObjCProtocolDecl*)); + + for (auto typeArg : typeArgs) { + if (typeArg->isDependentType()) + setDependent(); + else if (typeArg->isInstantiationDependentType()) + setInstantiationDependent(); + + if (typeArg->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + } +} + +bool ObjCObjectType::isSpecialized() const { + // If we have type arguments written here, the type is specialized. + if (ObjCObjectTypeBits.NumTypeArgs > 0) + return true; + + // Otherwise, check whether the base type is specialized. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + // Terminate when we reach an interface type. + if (isa<ObjCInterfaceType>(objcObject)) + return false; + + return objcObject->isSpecialized(); + } + + // Not specialized. + return false; +} + +ArrayRef<QualType> ObjCObjectType::getTypeArgs() const { + // We have type arguments written on this type. + if (isSpecializedAsWritten()) + return getTypeArgsAsWritten(); + + // Look at the base type, which might have type arguments. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + // Terminate when we reach an interface type. + if (isa<ObjCInterfaceType>(objcObject)) + return { }; + + return objcObject->getTypeArgs(); + } + + // No type arguments. + return { }; +} + +bool ObjCObjectType::isKindOfType() const { + if (isKindOfTypeAsWritten()) + return true; + + // Look at the base type, which might have type arguments. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + // Terminate when we reach an interface type. + if (isa<ObjCInterfaceType>(objcObject)) + return false; + + return objcObject->isKindOfType(); + } + + // Not a "__kindof" type. + return false; +} + +QualType ObjCObjectType::stripObjCKindOfTypeAndQuals( + const ASTContext &ctx) const { + if (!isKindOfType() && qual_empty()) + return QualType(this, 0); + + // Recursively strip __kindof. + SplitQualType splitBaseType = getBaseType().split(); + QualType baseType(splitBaseType.Ty, 0); + if (const ObjCObjectType *baseObj + = splitBaseType.Ty->getAs<ObjCObjectType>()) { + baseType = baseObj->stripObjCKindOfTypeAndQuals(ctx); + } + + return ctx.getObjCObjectType(ctx.getQualifiedType(baseType, + splitBaseType.Quals), + getTypeArgsAsWritten(), + /*protocols=*/{ }, + /*isKindOf=*/false); +} + +const ObjCObjectPointerType *ObjCObjectPointerType::stripObjCKindOfTypeAndQuals( + const ASTContext &ctx) const { + if (!isKindOfType() && qual_empty()) + return this; + + QualType obj = getObjectType()->stripObjCKindOfTypeAndQuals(ctx); + return ctx.getObjCObjectPointerType(obj)->castAs<ObjCObjectPointerType>(); +} + +namespace { + +template<typename F> +QualType simpleTransform(ASTContext &ctx, QualType type, F &&f); + +/// Visitor used by simpleTransform() to perform the transformation. +template<typename F> +struct SimpleTransformVisitor + : public TypeVisitor<SimpleTransformVisitor<F>, QualType> { + ASTContext &Ctx; + F &&TheFunc; + + QualType recurse(QualType type) { + return simpleTransform(Ctx, type, std::move(TheFunc)); + } + +public: + SimpleTransformVisitor(ASTContext &ctx, F &&f) : Ctx(ctx), TheFunc(std::move(f)) { } + + // None of the clients of this transformation can occur where + // there are dependent types, so skip dependent types. +#define TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) \ + QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); } +#include "clang/AST/TypeNodes.def" + +#define TRIVIAL_TYPE_CLASS(Class) \ + QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); } + + TRIVIAL_TYPE_CLASS(Builtin) + + QualType VisitComplexType(const ComplexType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getComplexType(elementType); + } + + QualType VisitPointerType(const PointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getPointerType(pointeeType); + } + + QualType VisitBlockPointerType(const BlockPointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getBlockPointerType(pointeeType); + } + + QualType VisitLValueReferenceType(const LValueReferenceType *T) { + QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() + == T->getPointeeTypeAsWritten().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getLValueReferenceType(pointeeType, T->isSpelledAsLValue()); + } + + QualType VisitRValueReferenceType(const RValueReferenceType *T) { + QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() + == T->getPointeeTypeAsWritten().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getRValueReferenceType(pointeeType); + } + + QualType VisitMemberPointerType(const MemberPointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getMemberPointerType(pointeeType, T->getClass()); + } + + QualType VisitConstantArrayType(const ConstantArrayType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getConstantArrayType(elementType, T->getSize(), + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + } + + QualType VisitVariableArrayType(const VariableArrayType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getVariableArrayType(elementType, T->getSizeExpr(), + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); + } + + QualType VisitIncompleteArrayType(const IncompleteArrayType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getIncompleteArrayType(elementType, T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + } + + QualType VisitVectorType(const VectorType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getVectorType(elementType, T->getNumElements(), + T->getVectorKind()); + } + + QualType VisitExtVectorType(const ExtVectorType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getExtVectorType(elementType, T->getNumElements()); + } + + QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T) { + QualType returnType = recurse(T->getReturnType()); + if (returnType.isNull()) + return QualType(); + + if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getFunctionNoProtoType(returnType, T->getExtInfo()); + } + + QualType VisitFunctionProtoType(const FunctionProtoType *T) { + QualType returnType = recurse(T->getReturnType()); + if (returnType.isNull()) + return QualType(); + + // Transform parameter types. + SmallVector<QualType, 4> paramTypes; + bool paramChanged = false; + for (auto paramType : T->getParamTypes()) { + QualType newParamType = recurse(paramType); + if (newParamType.isNull()) + return QualType(); + + if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) + paramChanged = true; + + paramTypes.push_back(newParamType); + } + + // Transform extended info. + FunctionProtoType::ExtProtoInfo info = T->getExtProtoInfo(); + bool exceptionChanged = false; + if (info.ExceptionSpec.Type == EST_Dynamic) { + SmallVector<QualType, 4> exceptionTypes; + for (auto exceptionType : info.ExceptionSpec.Exceptions) { + QualType newExceptionType = recurse(exceptionType); + if (newExceptionType.isNull()) + return QualType(); + + if (newExceptionType.getAsOpaquePtr() + != exceptionType.getAsOpaquePtr()) + exceptionChanged = true; + + exceptionTypes.push_back(newExceptionType); + } + + if (exceptionChanged) { + unsigned size = sizeof(QualType) * exceptionTypes.size(); + void *mem = Ctx.Allocate(size, llvm::alignOf<QualType>()); + memcpy(mem, exceptionTypes.data(), size); + info.ExceptionSpec.Exceptions + = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size()); + } + } + + if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr() && + !paramChanged && !exceptionChanged) + return QualType(T, 0); + + return Ctx.getFunctionType(returnType, paramTypes, info); + } + + QualType VisitParenType(const ParenType *T) { + QualType innerType = recurse(T->getInnerType()); + if (innerType.isNull()) + return QualType(); + + if (innerType.getAsOpaquePtr() == T->getInnerType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getParenType(innerType); + } + + TRIVIAL_TYPE_CLASS(Typedef) + + QualType VisitAdjustedType(const AdjustedType *T) { + QualType originalType = recurse(T->getOriginalType()); + if (originalType.isNull()) + return QualType(); + + QualType adjustedType = recurse(T->getAdjustedType()); + if (adjustedType.isNull()) + return QualType(); + + if (originalType.getAsOpaquePtr() + == T->getOriginalType().getAsOpaquePtr() && + adjustedType.getAsOpaquePtr() == T->getAdjustedType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAdjustedType(originalType, adjustedType); + } + + QualType VisitDecayedType(const DecayedType *T) { + QualType originalType = recurse(T->getOriginalType()); + if (originalType.isNull()) + return QualType(); + + if (originalType.getAsOpaquePtr() + == T->getOriginalType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getDecayedType(originalType); + } + + TRIVIAL_TYPE_CLASS(TypeOfExpr) + TRIVIAL_TYPE_CLASS(TypeOf) + TRIVIAL_TYPE_CLASS(Decltype) + TRIVIAL_TYPE_CLASS(UnaryTransform) + TRIVIAL_TYPE_CLASS(Record) + TRIVIAL_TYPE_CLASS(Enum) + + // FIXME: Non-trivial to implement, but important for C++ + TRIVIAL_TYPE_CLASS(Elaborated) + + QualType VisitAttributedType(const AttributedType *T) { + QualType modifiedType = recurse(T->getModifiedType()); + if (modifiedType.isNull()) + return QualType(); + + QualType equivalentType = recurse(T->getEquivalentType()); + if (equivalentType.isNull()) + return QualType(); + + if (modifiedType.getAsOpaquePtr() + == T->getModifiedType().getAsOpaquePtr() && + equivalentType.getAsOpaquePtr() + == T->getEquivalentType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAttributedType(T->getAttrKind(), modifiedType, + equivalentType); + } + + QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { + QualType replacementType = recurse(T->getReplacementType()); + if (replacementType.isNull()) + return QualType(); + + if (replacementType.getAsOpaquePtr() + == T->getReplacementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(), + replacementType); + } + + // FIXME: Non-trivial to implement, but important for C++ + TRIVIAL_TYPE_CLASS(TemplateSpecialization) + + QualType VisitAutoType(const AutoType *T) { + if (!T->isDeduced()) + return QualType(T, 0); + + QualType deducedType = recurse(T->getDeducedType()); + if (deducedType.isNull()) + return QualType(); + + if (deducedType.getAsOpaquePtr() + == T->getDeducedType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAutoType(deducedType, T->isDecltypeAuto(), + T->isDependentType()); + } + + // FIXME: Non-trivial to implement, but important for C++ + TRIVIAL_TYPE_CLASS(PackExpansion) + + QualType VisitObjCObjectType(const ObjCObjectType *T) { + QualType baseType = recurse(T->getBaseType()); + if (baseType.isNull()) + return QualType(); + + // Transform type arguments. + bool typeArgChanged = false; + SmallVector<QualType, 4> typeArgs; + for (auto typeArg : T->getTypeArgsAsWritten()) { + QualType newTypeArg = recurse(typeArg); + if (newTypeArg.isNull()) + return QualType(); + + if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) + typeArgChanged = true; + + typeArgs.push_back(newTypeArg); + } + + if (baseType.getAsOpaquePtr() == T->getBaseType().getAsOpaquePtr() && + !typeArgChanged) + return QualType(T, 0); + + return Ctx.getObjCObjectType(baseType, typeArgs, + llvm::makeArrayRef(T->qual_begin(), + T->getNumProtocols()), + T->isKindOfTypeAsWritten()); + } + + TRIVIAL_TYPE_CLASS(ObjCInterface) + + QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() + == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getObjCObjectPointerType(pointeeType); + } + + QualType VisitAtomicType(const AtomicType *T) { + QualType valueType = recurse(T->getValueType()); + if (valueType.isNull()) + return QualType(); + + if (valueType.getAsOpaquePtr() + == T->getValueType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAtomicType(valueType); + } + +#undef TRIVIAL_TYPE_CLASS +}; + +/// Perform a simple type transformation that does not change the +/// semantics of the type. +template<typename F> +QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) { + // Transform the type. If it changed, return the transformed result. + QualType transformed = f(type); + if (transformed.getAsOpaquePtr() != type.getAsOpaquePtr()) + return transformed; + + // Split out the qualifiers from the type. + SplitQualType splitType = type.split(); + + // Visit the type itself. + SimpleTransformVisitor<F> visitor(ctx, std::move(f)); + QualType result = visitor.Visit(splitType.Ty); + if (result.isNull()) + return result; + + // Reconstruct the transformed type by applying the local qualifiers + // from the split type. + return ctx.getQualifiedType(result, splitType.Quals); +} + +} // end anonymous namespace + +/// Substitute the given type arguments for Objective-C type +/// parameters within the given type, recursively. +QualType QualType::substObjCTypeArgs( + ASTContext &ctx, + ArrayRef<QualType> typeArgs, + ObjCSubstitutionContext context) const { + return simpleTransform(ctx, *this, + [&](QualType type) -> QualType { + SplitQualType splitType = type.split(); + + // Replace an Objective-C type parameter reference with the corresponding + // type argument. + if (const auto *typedefTy = dyn_cast<TypedefType>(splitType.Ty)) { + if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(typedefTy->getDecl())) { + // If we have type arguments, use them. + if (!typeArgs.empty()) { + // FIXME: Introduce SubstObjCTypeParamType ? + QualType argType = typeArgs[typeParam->getIndex()]; + return ctx.getQualifiedType(argType, splitType.Quals); + } + + switch (context) { + case ObjCSubstitutionContext::Ordinary: + case ObjCSubstitutionContext::Parameter: + case ObjCSubstitutionContext::Superclass: + // Substitute the bound. + return ctx.getQualifiedType(typeParam->getUnderlyingType(), + splitType.Quals); + + case ObjCSubstitutionContext::Result: + case ObjCSubstitutionContext::Property: { + // Substitute the __kindof form of the underlying type. + const auto *objPtr = typeParam->getUnderlyingType() + ->castAs<ObjCObjectPointerType>(); + + // __kindof types, id, and Class don't need an additional + // __kindof. + if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType()) + return ctx.getQualifiedType(typeParam->getUnderlyingType(), + splitType.Quals); + + // Add __kindof. + const auto *obj = objPtr->getObjectType(); + QualType resultTy = ctx.getObjCObjectType(obj->getBaseType(), + obj->getTypeArgsAsWritten(), + obj->getProtocols(), + /*isKindOf=*/true); + + // Rebuild object pointer type. + resultTy = ctx.getObjCObjectPointerType(resultTy); + return ctx.getQualifiedType(resultTy, splitType.Quals); + } + } + } + } + + // If we have a function type, update the context appropriately. + if (const auto *funcType = dyn_cast<FunctionType>(splitType.Ty)) { + // Substitute result type. + QualType returnType = funcType->getReturnType().substObjCTypeArgs( + ctx, + typeArgs, + ObjCSubstitutionContext::Result); + if (returnType.isNull()) + return QualType(); + + // Handle non-prototyped functions, which only substitute into the result + // type. + if (isa<FunctionNoProtoType>(funcType)) { + // If the return type was unchanged, do nothing. + if (returnType.getAsOpaquePtr() + == funcType->getReturnType().getAsOpaquePtr()) + return type; + + // Otherwise, build a new type. + return ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo()); + } + + const auto *funcProtoType = cast<FunctionProtoType>(funcType); + + // Transform parameter types. + SmallVector<QualType, 4> paramTypes; + bool paramChanged = false; + for (auto paramType : funcProtoType->getParamTypes()) { + QualType newParamType = paramType.substObjCTypeArgs( + ctx, + typeArgs, + ObjCSubstitutionContext::Parameter); + if (newParamType.isNull()) + return QualType(); + + if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) + paramChanged = true; + + paramTypes.push_back(newParamType); + } + + // Transform extended info. + FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo(); + bool exceptionChanged = false; + if (info.ExceptionSpec.Type == EST_Dynamic) { + SmallVector<QualType, 4> exceptionTypes; + for (auto exceptionType : info.ExceptionSpec.Exceptions) { + QualType newExceptionType = exceptionType.substObjCTypeArgs( + ctx, + typeArgs, + ObjCSubstitutionContext::Ordinary); + if (newExceptionType.isNull()) + return QualType(); + + if (newExceptionType.getAsOpaquePtr() + != exceptionType.getAsOpaquePtr()) + exceptionChanged = true; + + exceptionTypes.push_back(newExceptionType); + } + + if (exceptionChanged) { + unsigned size = sizeof(QualType) * exceptionTypes.size(); + void *mem = ctx.Allocate(size, llvm::alignOf<QualType>()); + memcpy(mem, exceptionTypes.data(), size); + info.ExceptionSpec.Exceptions + = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size()); + } + } + + if (returnType.getAsOpaquePtr() + == funcProtoType->getReturnType().getAsOpaquePtr() && + !paramChanged && !exceptionChanged) + return type; + + return ctx.getFunctionType(returnType, paramTypes, info); + } + + // Substitute into the type arguments of a specialized Objective-C object + // type. + if (const auto *objcObjectType = dyn_cast<ObjCObjectType>(splitType.Ty)) { + if (objcObjectType->isSpecializedAsWritten()) { + SmallVector<QualType, 4> newTypeArgs; + bool anyChanged = false; + for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) { + QualType newTypeArg = typeArg.substObjCTypeArgs( + ctx, typeArgs, + ObjCSubstitutionContext::Ordinary); + if (newTypeArg.isNull()) + return QualType(); + + if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) { + // If we're substituting based on an unspecialized context type, + // produce an unspecialized type. + ArrayRef<ObjCProtocolDecl *> protocols( + objcObjectType->qual_begin(), + objcObjectType->getNumProtocols()); + if (typeArgs.empty() && + context != ObjCSubstitutionContext::Superclass) { + return ctx.getObjCObjectType( + objcObjectType->getBaseType(), { }, + protocols, + objcObjectType->isKindOfTypeAsWritten()); + } + + anyChanged = true; + } + + newTypeArgs.push_back(newTypeArg); + } + + if (anyChanged) { + ArrayRef<ObjCProtocolDecl *> protocols( + objcObjectType->qual_begin(), + objcObjectType->getNumProtocols()); + return ctx.getObjCObjectType(objcObjectType->getBaseType(), + newTypeArgs, protocols, + objcObjectType->isKindOfTypeAsWritten()); + } + } + + return type; + } + + return type; + }); +} + +QualType QualType::substObjCMemberType(QualType objectType, + const DeclContext *dc, + ObjCSubstitutionContext context) const { + if (auto subs = objectType->getObjCSubstitutions(dc)) + return substObjCTypeArgs(dc->getParentASTContext(), *subs, context); + + return *this; +} + +QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const { + // FIXME: Because ASTContext::getAttributedType() is non-const. + auto &ctx = const_cast<ASTContext &>(constCtx); + return simpleTransform(ctx, *this, + [&](QualType type) -> QualType { + SplitQualType splitType = type.split(); + if (auto *objType = splitType.Ty->getAs<ObjCObjectType>()) { + if (!objType->isKindOfType()) + return type; + + QualType baseType + = objType->getBaseType().stripObjCKindOfType(ctx); + return ctx.getQualifiedType( + ctx.getObjCObjectType(baseType, + objType->getTypeArgsAsWritten(), + objType->getProtocols(), + /*isKindOf=*/false), + splitType.Quals); + } + + return type; + }); +} + +Optional<ArrayRef<QualType>> Type::getObjCSubstitutions( + const DeclContext *dc) const { + // Look through method scopes. + if (auto method = dyn_cast<ObjCMethodDecl>(dc)) + dc = method->getDeclContext(); + + // Find the class or category in which the type we're substituting + // was declared. + const ObjCInterfaceDecl *dcClassDecl = dyn_cast<ObjCInterfaceDecl>(dc); + const ObjCCategoryDecl *dcCategoryDecl = nullptr; + ObjCTypeParamList *dcTypeParams = nullptr; + if (dcClassDecl) { + // If the class does not have any type parameters, there's no + // substitution to do. + dcTypeParams = dcClassDecl->getTypeParamList(); + if (!dcTypeParams) + return None; + } else { + // If we are in neither a class mor a category, there's no + // substitution to perform. + dcCategoryDecl = dyn_cast<ObjCCategoryDecl>(dc); + if (!dcCategoryDecl) + return None; + + // If the category does not have any type parameters, there's no + // substitution to do. + dcTypeParams = dcCategoryDecl->getTypeParamList(); + if (!dcTypeParams) + return None; + + dcClassDecl = dcCategoryDecl->getClassInterface(); + if (!dcClassDecl) + return None; + } + assert(dcTypeParams && "No substitutions to perform"); + assert(dcClassDecl && "No class context"); + + // Find the underlying object type. + const ObjCObjectType *objectType; + if (const auto *objectPointerType = getAs<ObjCObjectPointerType>()) { + objectType = objectPointerType->getObjectType(); + } else if (getAs<BlockPointerType>()) { + ASTContext &ctx = dc->getParentASTContext(); + objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, { }) + ->castAs<ObjCObjectType>();; + } else { + objectType = getAs<ObjCObjectType>(); + } + + /// Extract the class from the receiver object type. + ObjCInterfaceDecl *curClassDecl = objectType ? objectType->getInterface() + : nullptr; + if (!curClassDecl) { + // If we don't have a context type (e.g., this is "id" or some + // variant thereof), substitute the bounds. + return llvm::ArrayRef<QualType>(); + } + + // Follow the superclass chain until we've mapped the receiver type + // to the same class as the context. + while (curClassDecl != dcClassDecl) { + // Map to the superclass type. + QualType superType = objectType->getSuperClassType(); + if (superType.isNull()) { + objectType = nullptr; + break; + } + + objectType = superType->castAs<ObjCObjectType>(); + curClassDecl = objectType->getInterface(); + } + + // If we don't have a receiver type, or the receiver type does not + // have type arguments, substitute in the defaults. + if (!objectType || objectType->isUnspecialized()) { + return llvm::ArrayRef<QualType>(); + } + + // The receiver type has the type arguments we want. + return objectType->getTypeArgs(); +} + +bool Type::acceptsObjCTypeParams() const { + if (auto *IfaceT = getAsObjCInterfaceType()) { + if (auto *ID = IfaceT->getInterface()) { + if (ID->getTypeParamList()) + return true; + } + } + + return false; +} + +void ObjCObjectType::computeSuperClassTypeSlow() const { + // Retrieve the class declaration for this type. If there isn't one + // (e.g., this is some variant of "id" or "Class"), then there is no + // superclass type. + ObjCInterfaceDecl *classDecl = getInterface(); + if (!classDecl) { + CachedSuperClassType.setInt(true); + return; + } + + // Extract the superclass type. + const ObjCObjectType *superClassObjTy = classDecl->getSuperClassType(); + if (!superClassObjTy) { + CachedSuperClassType.setInt(true); + return; + } + + ObjCInterfaceDecl *superClassDecl = superClassObjTy->getInterface(); + if (!superClassDecl) { + CachedSuperClassType.setInt(true); + return; + } + + // If the superclass doesn't have type parameters, then there is no + // substitution to perform. + QualType superClassType(superClassObjTy, 0); + ObjCTypeParamList *superClassTypeParams = superClassDecl->getTypeParamList(); + if (!superClassTypeParams) { + CachedSuperClassType.setPointerAndInt( + superClassType->castAs<ObjCObjectType>(), true); + return; + } + + // If the superclass reference is unspecialized, return it. + if (superClassObjTy->isUnspecialized()) { + CachedSuperClassType.setPointerAndInt(superClassObjTy, true); + return; + } + + // If the subclass is not parameterized, there aren't any type + // parameters in the superclass reference to substitute. + ObjCTypeParamList *typeParams = classDecl->getTypeParamList(); + if (!typeParams) { + CachedSuperClassType.setPointerAndInt( + superClassType->castAs<ObjCObjectType>(), true); + return; + } + + // If the subclass type isn't specialized, return the unspecialized + // superclass. + if (isUnspecialized()) { + QualType unspecializedSuper + = classDecl->getASTContext().getObjCInterfaceType( + superClassObjTy->getInterface()); + CachedSuperClassType.setPointerAndInt( + unspecializedSuper->castAs<ObjCObjectType>(), + true); + return; + } + + // Substitute the provided type arguments into the superclass type. + ArrayRef<QualType> typeArgs = getTypeArgs(); + assert(typeArgs.size() == typeParams->size()); + CachedSuperClassType.setPointerAndInt( + superClassType.substObjCTypeArgs(classDecl->getASTContext(), typeArgs, + ObjCSubstitutionContext::Superclass) + ->castAs<ObjCObjectType>(), + true); +} + +const ObjCInterfaceType *ObjCObjectPointerType::getInterfaceType() const { + if (auto interfaceDecl = getObjectType()->getInterface()) { + return interfaceDecl->getASTContext().getObjCInterfaceType(interfaceDecl) + ->castAs<ObjCInterfaceType>(); + } + + return nullptr; +} + +QualType ObjCObjectPointerType::getSuperClassType() const { + QualType superObjectType = getObjectType()->getSuperClassType(); + if (superObjectType.isNull()) + return superObjectType; + + ASTContext &ctx = getInterfaceDecl()->getASTContext(); + return ctx.getObjCObjectPointerType(superObjectType); } const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { @@ -514,6 +1472,13 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const { return nullptr; } +const ObjCObjectType *Type::getAsObjCInterfaceType() const { + if (const ObjCObjectType *OT = getAs<ObjCObjectType>()) { + if (OT->getInterface()) + return OT; + } + return nullptr; +} const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { if (OPT->getInterfaceType()) @@ -1927,7 +2892,9 @@ bool AttributedType::isCallingConv() const { case attr_nonnull: case attr_nullable: case attr_null_unspecified: + case attr_objc_kindof: return false; + case attr_pcs: case attr_pcs_vfp: case attr_cdecl: @@ -2076,15 +3043,23 @@ QualifierCollector::apply(const ASTContext &Context, const Type *T) const { void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, - ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) { + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) { ID.AddPointer(BaseType.getAsOpaquePtr()); - for (unsigned i = 0; i != NumProtocols; i++) - ID.AddPointer(Protocols[i]); + ID.AddInteger(typeArgs.size()); + for (auto typeArg : typeArgs) + ID.AddPointer(typeArg.getAsOpaquePtr()); + ID.AddInteger(protocols.size()); + for (auto proto : protocols) + ID.AddPointer(proto); + ID.AddBoolean(isKindOf); } void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), qual_begin(), getNumProtocols()); + Profile(ID, getBaseType(), getTypeArgsAsWritten(), + llvm::makeArrayRef(qual_begin(), getNumProtocols()), + isKindOfTypeAsWritten()); } namespace { @@ -2495,6 +3470,39 @@ Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) { return None; } +bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const { + const ObjCObjectPointerType *objcPtr = getAs<ObjCObjectPointerType>(); + if (!objcPtr) + return false; + + if (objcPtr->isObjCIdType()) { + // id is always okay. + return true; + } + + // Blocks are NSObjects. + if (ObjCInterfaceDecl *iface = objcPtr->getInterfaceDecl()) { + if (iface->getIdentifier() != ctx.getNSObjectName()) + return false; + + // Continue to check qualifiers, below. + } else if (objcPtr->isObjCQualifiedIdType()) { + // Continue to check qualifiers, below. + } else { + return false; + } + + // Check protocol qualifiers. + for (ObjCProtocolDecl *proto : objcPtr->quals()) { + // Blocks conform to NSObject and NSCopying. + if (proto->getIdentifier() != ctx.getNSObjectName() && + proto->getIdentifier() != ctx.getNSCopyingName()) + return false; + } + + return true; +} + Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const { if (isObjCARCImplicitlyUnretainedType()) return Qualifiers::OCL_ExplicitNone; diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index c069eb061739..85bda6a06d97 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -19,6 +19,8 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +static const unsigned TypeLocMaxDataAlign = llvm::alignOf<void *>(); + //===----------------------------------------------------------------------===// // TypeLoc Implementation //===----------------------------------------------------------------------===// @@ -125,6 +127,46 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, } } +namespace { + class TypeLocCopier : public TypeLocVisitor<TypeLocCopier> { + TypeLoc Source; + public: + TypeLocCopier(TypeLoc source) : Source(source) { } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) { \ + dest.copyLocal(Source.castAs<CLASS##TypeLoc>()); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + + +void TypeLoc::copy(TypeLoc other) { + assert(getFullDataSize() == other.getFullDataSize()); + + // If both data pointers are aligned to the maximum alignment, we + // can memcpy because getFullDataSize() accurately reflects the + // layout of the data. + if (reinterpret_cast<uintptr_t>(Data) + == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(Data), + TypeLocMaxDataAlign) && + reinterpret_cast<uintptr_t>(other.Data) + == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(other.Data), + TypeLocMaxDataAlign)) { + memcpy(Data, other.Data, getFullDataSize()); + return; + } + + // Copy each of the pieces. + TypeLoc TL(getType(), Data); + do { + TypeLocCopier(other).Visit(TL); + other = other.getNextTypeLoc(); + } while ((TL = TL.getNextTypeLoc())); +} + SourceLocation TypeLoc::getBeginLoc() const { TypeLoc Cur = *this; TypeLoc LeftMost = Cur; @@ -312,6 +354,33 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { return TL; } +SourceLocation TypeLoc::findNullabilityLoc() const { + if (auto attributedLoc = getAs<AttributedTypeLoc>()) { + if (attributedLoc.getAttrKind() == AttributedType::attr_nullable || + attributedLoc.getAttrKind() == AttributedType::attr_nonnull || + attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified) + return attributedLoc.getAttrNameLoc(); + } + + return SourceLocation(); +} + +void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setHasBaseTypeAsWritten(true); + setTypeArgsLAngleLoc(Loc); + setTypeArgsRAngleLoc(Loc); + for (unsigned i = 0, e = getNumTypeArgs(); i != e; ++i) { + setTypeArgTInfo(i, + Context.getTrivialTypeSourceInfo( + getTypePtr()->getTypeArgsAsWritten()[i], Loc)); + } + setProtocolLAngleLoc(Loc); + setProtocolRAngleLoc(Loc); + for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) + setProtocolLoc(i, Loc); +} + void TypeOfTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 9938170c321a..0bb50c6ba815 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -1129,6 +1129,9 @@ void TypePrinter::printAttributedBefore(const AttributedType *T, T->getAttrKind() == AttributedType::attr_objc_ownership) return printBefore(T->getEquivalentType(), OS); + if (T->getAttrKind() == AttributedType::attr_objc_kindof) + OS << "__kindof "; + printBefore(T->getModifiedType(), OS); if (T->isMSTypeSpec()) { @@ -1165,6 +1168,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, T->getAttrKind() == AttributedType::attr_objc_ownership) return printAfter(T->getEquivalentType(), OS); + if (T->getAttrKind() == AttributedType::attr_objc_kindof) + return; + // TODO: not all attributes are GCC-style attributes. if (T->isMSTypeSpec()) return; @@ -1310,59 +1316,61 @@ void TypePrinter::printObjCInterfaceAfter(const ObjCInterfaceType *T, void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T, raw_ostream &OS) { - if (T->qual_empty()) + if (T->qual_empty() && T->isUnspecializedAsWritten() && + !T->isKindOfTypeAsWritten()) return printBefore(T->getBaseType(), OS); + if (T->isKindOfTypeAsWritten()) + OS << "__kindof "; + print(T->getBaseType(), OS, StringRef()); - OS << '<'; - bool isFirst = true; - for (const auto *I : T->quals()) { - if (isFirst) - isFirst = false; - else - OS << ','; - OS << I->getName(); + + if (T->isSpecializedAsWritten()) { + bool isFirst = true; + OS << '<'; + for (auto typeArg : T->getTypeArgsAsWritten()) { + if (isFirst) + isFirst = false; + else + OS << ","; + + print(typeArg, OS, StringRef()); + } + OS << '>'; } - OS << '>'; + + if (!T->qual_empty()) { + bool isFirst = true; + OS << '<'; + for (const auto *I : T->quals()) { + if (isFirst) + isFirst = false; + else + OS << ','; + OS << I->getName(); + } + OS << '>'; + } + spaceBeforePlaceHolder(OS); } void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T, raw_ostream &OS) { - if (T->qual_empty()) + if (T->qual_empty() && T->isUnspecializedAsWritten() && + !T->isKindOfTypeAsWritten()) return printAfter(T->getBaseType(), OS); } void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T, raw_ostream &OS) { - T->getPointeeType().getLocalQualifiers().print(OS, Policy, - /*appendSpaceIfNonEmpty=*/true); - - assert(!T->isObjCSelType()); + printBefore(T->getPointeeType(), OS); - if (T->isObjCIdType() || T->isObjCQualifiedIdType()) - OS << "id"; - else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) - OS << "Class"; - else - OS << T->getInterfaceDecl()->getName(); - - if (!T->qual_empty()) { - OS << '<'; - for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(), - E = T->qual_end(); - I != E; ++I) { - OS << (*I)->getName(); - if (I+1 != E) - OS << ','; - } - OS << '>'; - } - + // If we need to print the pointer, print it now. if (!T->isObjCIdType() && !T->isObjCQualifiedIdType() && !T->isObjCClassType() && !T->isObjCQualifiedClassType()) { - OS << " *"; // Don't forget the implicit pointer. - } else { - spaceBeforePlaceHolder(OS); + if (HasEmptyPlaceHolder) + OS << ' '; + OS << '*'; } } void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T, diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp index b6ef8226a9a9..069fcba474b2 100644 --- a/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -20,21 +20,21 @@ namespace clang { namespace ast_matchers { namespace internal { -bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, +bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); -bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); @@ -51,7 +51,7 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { namespace { typedef bool (*VariadicOperatorFunction)( - const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, + const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); template <VariadicOperatorFunction Func> @@ -228,7 +228,7 @@ void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { Bindings.append(Other.Bindings.begin(), Other.Bindings.end()); } -bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, +bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { if (InnerMatchers.size() != 1) @@ -248,7 +248,7 @@ bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, return !InnerMatchers[0].matches(DynNode, Finder, &Discard); } -bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { @@ -262,7 +262,7 @@ bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, return true; } -bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { @@ -279,7 +279,7 @@ bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, return Matched; } -bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, +bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp index 9930c530c081..96a78cd9f8fa 100644 --- a/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/lib/ASTMatchers/Dynamic/Parser.cpp @@ -216,7 +216,7 @@ private: if (Code[Length] == Marker) { Result->Kind = TokenInfo::TK_Literal; Result->Text = Code.substr(0, Length + 1); - Result->Value = Code.substr(1, Length - 1).str(); + Result->Value = Code.substr(1, Length - 1); Code = Code.drop_front(Length + 1); return; } diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp index a88b70701234..9d8be4700581 100644 --- a/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -249,7 +249,7 @@ VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) { setUnsigned(Unsigned); } -VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) { +VariantValue::VariantValue(StringRef String) : Type(VT_Nothing) { setString(String); } @@ -319,7 +319,7 @@ const std::string &VariantValue::getString() const { return *Value.String; } -void VariantValue::setString(const std::string &NewValue) { +void VariantValue::setString(StringRef NewValue) { reset(); Type = VT_String; Value.String = new std::string(NewValue); diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index c46e2c7db380..1a636aefa639 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" +#include "clang/Frontend/PCHContainerOperations.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/FileSystem.h" @@ -585,3 +586,5 @@ void FileManager::PrintStats() const { //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; } + +PCHContainerOperations::~PCHContainerOperations() {} diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 36fba994f1e7..dcb7603bf5ab 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -109,7 +109,8 @@ namespace { WCHARSUPPORT = 0x04000, HALFSUPPORT = 0x08000, KEYCONCEPTS = 0x10000, - KEYALL = (0x1ffff & ~KEYNOMS18 & + KEYOBJC2 = 0x20000, + KEYALL = (0x3ffff & ~KEYNOMS18 & ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. }; @@ -144,6 +145,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, // in non-arc mode. if (LangOpts.ObjC2 && (Flags & KEYARC)) return KS_Enabled; if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled; + if (LangOpts.ObjC2 && (Flags & KEYOBJC2)) return KS_Enabled; if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) return KS_Future; return KS_Disabled; } diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 1a48a6c6a8d1..3846fecebf5d 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -82,10 +82,6 @@ bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target, return true; for (const Module *Current = this; Current; Current = Current->Parent) { - if (!Current->MissingHeaders.empty()) { - MissingHeader = Current->MissingHeaders.front(); - return false; - } for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) { if (hasFeature(Current->Requirements[I].first, LangOpts, Target) != Current->Requirements[I].second) { @@ -93,6 +89,10 @@ bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target, return false; } } + if (!Current->MissingHeaders.empty()) { + MissingHeader = Current->MissingHeaders.front(); + return false; + } } llvm_unreachable("could not find a reason why module is unavailable"); @@ -184,7 +184,11 @@ void Module::addRequirement(StringRef Feature, bool RequiredState, } void Module::markUnavailable(bool MissingRequirement) { - if (!IsAvailable) + auto needUpdate = [MissingRequirement](Module *M) { + return M->IsAvailable || (!M->IsMissingRequirement && MissingRequirement); + }; + + if (!needUpdate(this)) return; SmallVector<Module *, 2> Stack; @@ -193,7 +197,7 @@ void Module::markUnavailable(bool MissingRequirement) { Module *Current = Stack.back(); Stack.pop_back(); - if (!Current->IsAvailable) + if (!needUpdate(Current)) continue; Current->IsAvailable = false; @@ -201,7 +205,7 @@ void Module::markUnavailable(bool MissingRequirement) { for (submodule_iterator Sub = Current->submodule_begin(), SubEnd = Current->submodule_end(); Sub != SubEnd; ++Sub) { - if ((*Sub)->IsAvailable) + if (needUpdate(*Sub)) Stack.push_back(*Sub); } } diff --git a/lib/Basic/Sanitizers.cpp b/lib/Basic/Sanitizers.cpp index d3676b6b465c..91b6b2dc74eb 100644 --- a/lib/Basic/Sanitizers.cpp +++ b/lib/Basic/Sanitizers.cpp @@ -14,34 +14,9 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/MathExtras.h" using namespace clang; -SanitizerSet::SanitizerSet() : Mask(0) {} - -bool SanitizerSet::has(SanitizerMask K) const { - assert(llvm::countPopulation(K) == 1); - return Mask & K; -} - -bool SanitizerSet::hasOneOf(SanitizerMask K) const { - return Mask & K; -} - -void SanitizerSet::set(SanitizerMask K, bool Value) { - assert(llvm::countPopulation(K) == 1); - Mask = Value ? (Mask | K) : (Mask & ~K); -} - -void SanitizerSet::clear() { - Mask = 0; -} - -bool SanitizerSet::empty() const { - return Mask == 0; -} - SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) { SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value) #define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID) diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 856ad50d3782..dbd2f9ae9954 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -50,6 +50,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { LargeArrayAlign = 0; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; MaxVectorAlign = 0; + MaxTLSAlign = 0; SimdDefaultAlign = 0; SizeType = UnsignedLong; PtrDiffType = SignedLong; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 8f2bca051b67..3cf74bc84926 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -580,6 +580,8 @@ public: PS4OSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { this->WCharType = this->UnsignedShort; + // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits). + this->MaxTLSAlign = 256; this->UserLabelPrefix = ""; switch (Triple.getArch()) { @@ -863,6 +865,8 @@ public: bool handleTargetFeatures(std::vector<std::string> &Features, DiagnosticsEngine &Diags) override; bool hasFeature(StringRef Feature) const override; + void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, + bool Enabled) const override; void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const override; @@ -1036,7 +1040,6 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, if (Feature == "power8-vector") { HasP8Vector = true; - HasVSX = true; continue; } @@ -1047,7 +1050,6 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, if (Feature == "direct-move") { HasDirectMove = true; - HasVSX = true; continue; } @@ -1064,6 +1066,15 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, // TODO: Finish this list and add an assert that we've handled them // all. } + if (!HasVSX && (HasP8Vector || HasDirectMove)) { + if (HasP8Vector) + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" << + "-mno-vsx"; + else if (HasDirectMove) + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" << + "-mno-vsx"; + return false; + } return true; } @@ -1285,6 +1296,11 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { .Case("ppc64le", true) .Case("pwr8", true) .Default(false); + Features["vsx"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); } bool PPCTargetInfo::hasFeature(StringRef Feature) const { @@ -1301,6 +1317,39 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const { .Default(false); } +/* There is no clear way for the target to know which of the features in the + final feature vector came from defaults and which are actually specified by + the user. To that end, we use the fact that this function is not called on + default features - only user specified ones. By the first time this + function is called, the default features are populated. + We then keep track of the features that the user specified so that we + can ensure we do not override a user's request (only defaults). + For example: + -mcpu=pwr8 -mno-vsx (should disable vsx and everything that depends on it) + -mcpu=pwr8 -mdirect-move -mno-vsx (should actually be diagnosed) + +NOTE: Do not call this from PPCTargetInfo::getDefaultFeatures +*/ +void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled) const { + static llvm::StringMap<bool> ExplicitFeatures; + ExplicitFeatures[Name] = Enabled; + + // At this point, -mno-vsx turns off the dependent features but we respect + // the user's requests. + if (!Enabled && Name == "vsx") { + Features["direct-move"] = ExplicitFeatures["direct-move"]; + Features["power8-vector"] = ExplicitFeatures["power8-vector"]; + } + if ((Enabled && Name == "power8-vector") || + (Enabled && Name == "direct-move")) { + if (ExplicitFeatures.find("vsx") == ExplicitFeatures.end()) { + Features["vsx"] = true; + } + } + Features[Name] = Enabled; +} + const char * const PPCTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", @@ -1472,7 +1521,7 @@ public: BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } - // PPC64 Linux-specifc ABI options. + // PPC64 Linux-specific ABI options. bool setABI(const std::string &Name) override { if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") { ABI = Name; @@ -3996,14 +4045,8 @@ class ARMTargetInfo : public TargetInfo { FP_Neon } FPMath; - unsigned ArchISA; - unsigned ArchKind; - unsigned ArchProfile; - unsigned ArchVersion; - unsigned FPU : 5; - unsigned ShouldUseInlineAtomic : 1; unsigned IsAAPCS : 1; unsigned IsThumb : 1; unsigned HWDiv : 2; @@ -4025,6 +4068,37 @@ class ARMTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; + static bool shouldUseInlineAtomic(const llvm::Triple &T) { + StringRef ArchName = T.getArchName(); + if (T.getArch() == llvm::Triple::arm || + T.getArch() == llvm::Triple::armeb) { + StringRef VersionStr; + if (ArchName.startswith("armv")) + VersionStr = ArchName.substr(4, 1); + else if (ArchName.startswith("armebv")) + VersionStr = ArchName.substr(6, 1); + else + return false; + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 6; + } + assert(T.getArch() == llvm::Triple::thumb || + T.getArch() == llvm::Triple::thumbeb); + StringRef VersionStr; + if (ArchName.startswith("thumbv")) + VersionStr = ArchName.substr(6, 1); + else if (ArchName.startswith("thumbebv")) + VersionStr = ArchName.substr(8, 1); + else + return false; + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 7; + } + void setABIAAPCS() { IsAAPCS = true; @@ -4123,27 +4197,6 @@ class ARMTargetInfo : public TargetInfo { // FIXME: Override "preferred align" for double and long long. } - void setArchInfo(StringRef ArchName) { - ArchISA = llvm::ARMTargetParser::parseArchISA(ArchName); - ArchKind = llvm::ARMTargetParser::parseArch(ArchName); - ArchProfile = llvm::ARMTargetParser::parseArchProfile(ArchName); - ArchVersion = llvm::ARMTargetParser::parseArchVersion(ArchName); - } - - void setAtomic() { - // Cortex M does not support 8 byte atomics, while general Thumb2 does. - if (ArchProfile == llvm::ARM::PK_M) { - MaxAtomicPromoteWidth = 32; - if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 32; - } - else { - MaxAtomicPromoteWidth = 64; - if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 64; - } - } - public: ARMTargetInfo(const llvm::Triple &Triple, bool IsBigEndian) : TargetInfo(Triple), CPU("arm1136j-s"), FPMath(FP_Default), @@ -4159,27 +4212,12 @@ public: break; } - // if subArch is not specified Arc Info is based on the default CPU - if (Triple.getSubArch() == llvm::Triple::SubArchType::NoSubArch) { - unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(CPU); - setArchInfo(llvm::ARMTargetParser::getArchName(ArchKind)); - ShouldUseInlineAtomic = false; - } - else { - setArchInfo(Triple.getArchName()); - // FIXME: Should't this be updated also when calling setCPU() ? - // Doing so currently causes regressions - ShouldUseInlineAtomic = (ArchISA == llvm::ARM::IK_ARM && ArchVersion >= 6) || - (ArchISA == llvm::ARM::IK_THUMB && ArchVersion >= 7); - } - // {} in inline assembly are neon specifiers, not assembly variant // specifiers. NoAsmVariants = true; - // FIXME: Should't this be updated also when calling setCPU() ? - // Doing so currently causes regressions - IsThumb = (ArchISA == llvm::ARM::IK_THUMB); + // FIXME: Should we just treat this as a feature? + IsThumb = getTriple().getArchName().startswith("thumb"); // FIXME: This duplicates code from the driver that sets the -target-abi // option - this code is used if -target-abi isn't passed and should @@ -4224,7 +4262,10 @@ public: // ARM targets default to using the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::GenericARM); - setAtomic(); + // ARM has atomics up to 8 bytes + MaxAtomicPromoteWidth = 64; + if (shouldUseInlineAtomic(getTriple())) + MaxAtomicInlineWidth = 64; // Do force alignment of members that follow zero length bitfields. If // the alignment of the zero-length bitfield is greater than the member @@ -4255,6 +4296,11 @@ public: // FIXME: This should be based on Arch attributes, not CPU names. void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { + StringRef ArchName = getTriple().getArchName(); + unsigned ArchKind = llvm::ARMTargetParser::parseArch(ArchName); + bool IsV8 = (ArchKind == llvm::ARM::AK_ARMV8A || + ArchKind == llvm::ARM::AK_ARMV8_1A); + if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore") Features["vfp2"] = true; else if (CPU == "cortex-a8" || CPU == "cortex-a9") { @@ -4279,7 +4325,7 @@ public: Features["hwdiv-arm"] = true; Features["crc"] = true; Features["crypto"] = true; - } else if (CPU == "cortex-r5" || CPU == "cortex-r7" || ArchVersion == 8) { + } else if (CPU == "cortex-r5" || CPU == "cortex-r7" || IsV8) { Features["hwdiv"] = true; Features["hwdiv-arm"] = true; } else if (CPU == "cortex-m3" || CPU == "cortex-m4" || CPU == "cortex-m7" || @@ -4362,14 +4408,26 @@ public: .Case("hwdiv-arm", HWDiv & HWDivARM) .Default(false); } - const char *getCPUAttr() const { - const char *CPUAttr; + const char *getCPUDefineSuffix(StringRef Name) const { + if(Name == "generic") { + auto subarch = getTriple().getSubArch(); + switch (subarch) { + case llvm::Triple::SubArchType::ARMSubArch_v8_1a: + return "8_1A"; + default: + break; + } + } + + unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(Name); + if (ArchKind == llvm::ARM::AK_INVALID) + return ""; + // For most sub-arches, the build attribute CPU name is enough. // For Cortex variants, it's slightly different. switch(ArchKind) { default: - CPUAttr = llvm::ARMTargetParser::getCPUAttr(ArchKind); - return CPUAttr ? CPUAttr : "" ; + return llvm::ARMTargetParser::getCPUAttr(ArchKind); case llvm::ARM::AK_ARMV6M: case llvm::ARM::AK_ARMV6SM: return "6M"; @@ -4389,8 +4447,23 @@ public: return "8_1A"; } } - const char *getCPUProfile() const { - switch(ArchProfile) { + const char *getCPUProfile(StringRef Name) const { + if(Name == "generic") { + auto subarch = getTriple().getSubArch(); + switch (subarch) { + case llvm::Triple::SubArchType::ARMSubArch_v8_1a: + return "A"; + default: + break; + } + } + + unsigned CPUArch = llvm::ARMTargetParser::parseCPUArch(Name); + if (CPUArch == llvm::ARM::AK_INVALID) + return ""; + + StringRef ArchName = llvm::ARMTargetParser::getArchName(CPUArch); + switch(llvm::ARMTargetParser::parseArchProfile(ArchName)) { case llvm::ARM::PK_A: return "A"; case llvm::ARM::PK_R: @@ -4402,26 +4475,35 @@ public: } } bool setCPU(const std::string &Name) override { - unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(Name); - if (ArchKind == llvm::ARM::AK_INVALID) + if (!getCPUDefineSuffix(Name)) return false; - setArchInfo(llvm::ARMTargetParser::getArchName(ArchKind)); - setAtomic(); + + // Cortex M does not support 8 byte atomics, while general Thumb2 does. + StringRef Profile = getCPUProfile(Name); + if (Profile == "M" && MaxAtomicInlineWidth) { + MaxAtomicPromoteWidth = 32; + MaxAtomicInlineWidth = 32; + } + CPU = Name; return true; } bool setFPMath(StringRef Name) override; - bool supportsThumb(StringRef CPUAttr) const { - return CPUAttr.count('T') || ArchVersion >= 6; - } - bool supportsThumb2(StringRef CPUAttr) const { - return CPUAttr.equals("6T2") || ArchVersion >= 7; + bool supportsThumb(StringRef ArchName, StringRef CPUArch, + unsigned CPUArchVer) const { + return CPUArchVer >= 7 || (CPUArch.find('T') != StringRef::npos) || + (CPUArch.find('M') != StringRef::npos); + } + bool supportsThumb2(StringRef ArchName, StringRef CPUArch, + unsigned CPUArchVer) const { + // We check both CPUArchVer and ArchName because when only triple is + // specified, the default CPU is arm1136j-s. + return ArchName.endswith("v6t2") || ArchName.endswith("v7") || + ArchName.endswith("v8.1a") || + ArchName.endswith("v8") || CPUArch == "6T2" || CPUArchVer >= 7; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { - StringRef CPUAttr = getCPUAttr(); - StringRef CPUProfile = getCPUProfile(); - // Target identification. Builder.defineMacro("__arm"); Builder.defineMacro("__arm__"); @@ -4429,12 +4511,19 @@ public: // Target properties. Builder.defineMacro("__REGISTER_PREFIX__", ""); - Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__"); + StringRef CPUArch = getCPUDefineSuffix(CPU); + unsigned int CPUArchVer; + if (CPUArch.substr(0, 1).getAsInteger<unsigned int>(10, CPUArchVer)) + llvm_unreachable("Invalid char for architecture version number"); + Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__"); // ACLE 6.4.1 ARM/Thumb instruction set architecture + StringRef CPUProfile = getCPUProfile(CPU); + StringRef ArchName = getTriple().getArchName(); + // __ARM_ARCH is defined as an integer value indicating the current ARM ISA - Builder.defineMacro("__ARM_ARCH", std::to_string(ArchVersion)); - if (ArchVersion >= 8) { + Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1)); + if (CPUArch[0] >= '8') { Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN"); Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING"); } @@ -4448,9 +4537,9 @@ public: // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supporst the original // Thumb ISA (including v6-M). It is set to 2 if the core supports the // Thumb-2 ISA as found in the v6T2 architecture and all v7 architecture. - if (supportsThumb2(CPUAttr)) + if (supportsThumb2(ArchName, CPUArch, CPUArchVer)) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); - else if (supportsThumb(CPUAttr)) + else if (supportsThumb(ArchName, CPUArch, CPUArchVer)) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1"); // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit @@ -4475,7 +4564,7 @@ public: // FIXME: It's more complicated than this and we don't really support // interworking. // Windows on ARM does not "support" interworking - if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows()) + if (5 <= CPUArchVer && CPUArchVer <= 8 && !getTriple().isOSWindows()) Builder.defineMacro("__THUMB_INTERWORK__"); if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { @@ -4498,7 +4587,7 @@ public: if (IsThumb) { Builder.defineMacro("__THUMBEL__"); Builder.defineMacro("__thumb__"); - if (supportsThumb2(CPUAttr)) + if (supportsThumb2(ArchName, CPUArch, CPUArchVer)) Builder.defineMacro("__thumb2__"); } if (((HWDiv & HWDivThumb) && IsThumb) || ((HWDiv & HWDivARM) && !IsThumb)) @@ -4521,7 +4610,7 @@ public: // the VFP define, hence the soft float and arch check. This is subtly // different from gcc, we follow the intent which was that it should be set // when Neon instructions are actually available. - if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) { + if ((FPU & NeonFPU) && !SoftFloat && CPUArchVer >= 7) { Builder.defineMacro("__ARM_NEON"); Builder.defineMacro("__ARM_NEON__"); } @@ -4538,18 +4627,18 @@ public: if (Crypto) Builder.defineMacro("__ARM_FEATURE_CRYPTO"); - if (ArchVersion >= 6 && CPUAttr != "6M") { + if (CPUArchVer >= 6 && CPUArch != "6M") { Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } - bool is5EOrAbove = (ArchVersion >= 6 || - (ArchVersion == 5 && CPUAttr.count('E'))); - // FIXME: We are not getting all 32-bit ARM architectures - bool is32Bit = (!IsThumb || supportsThumb2(CPUAttr)); - if (is5EOrAbove && is32Bit && (CPUProfile != "M" || CPUAttr == "7EM")) + bool is5EOrAbove = (CPUArchVer >= 6 || + (CPUArchVer == 5 && + CPUArch.find('E') != StringRef::npos)); + bool is32Bit = (!IsThumb || supportsThumb2(ArchName, CPUArch, CPUArchVer)); + if (is5EOrAbove && is32Bit && (CPUProfile != "M" || CPUArch == "7EM")) Builder.defineMacro("__ARM_FEATURE_DSP"); } void getTargetBuiltins(const Builtin::Info *&Records, @@ -6632,6 +6721,19 @@ void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, NumAliases = 0; } +// We attempt to use PNaCl (le32) frontend and Mips32EL backend. +class NaClMips32ELTargetInfo : public Mips32ELTargetInfo { +public: + NaClMips32ELTargetInfo(const llvm::Triple &Triple) : + Mips32ELTargetInfo(Triple) { + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } +}; + class Le64TargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; @@ -7002,7 +7104,7 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { case llvm::Triple::NetBSD: return new NetBSDTargetInfo<Mips32ELTargetInfo>(Triple); case llvm::Triple::NaCl: - return new NaClTargetInfo<Mips32ELTargetInfo>(Triple); + return new NaClTargetInfo<NaClMips32ELTargetInfo>(Triple); default: return new Mips32ELTargetInfo(Triple); } diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 0bccad0570da..afcb9e5c5055 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -292,6 +292,7 @@ void EmitAssemblyHelper::CreatePasses() { PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime; PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops; PMBuilder.MergeFunctions = CodeGenOpts.MergeFunctions; + PMBuilder.PrepareForLTO = CodeGenOpts.PrepareForLTO; PMBuilder.RerollLoops = CodeGenOpts.RerollLoops; PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible, @@ -454,8 +455,6 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { BackendArgs.push_back("-limit-float-precision"); BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); } - if (llvm::TimePassesIsEnabled) - BackendArgs.push_back("-time-passes"); for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i) BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str()); BackendArgs.push_back(nullptr); diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp index da82249fe114..9839617c0e41 100644 --- a/lib/CodeGen/CGAtomic.cpp +++ b/lib/CodeGen/CGAtomic.cpp @@ -93,6 +93,7 @@ namespace { BFI = OrigBFI; BFI.Offset = Offset; BFI.StorageSize = AtomicSizeInBits; + BFI.StorageOffset += OffsetInChars; LVal = LValue::MakeBitfield(Addr, BFI, lvalue.getType(), lvalue.getAlignment()); LVal.setTBAAInfo(lvalue.getTBAAInfo()); diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 2ec909b9aac5..9e538703177d 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -535,7 +535,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__builtin_readcyclecounter: { Value *F = CGM.getIntrinsic(Intrinsic::readcyclecounter); - return RValue::get(Builder.CreateCall(F, {})); + return RValue::get(Builder.CreateCall(F)); } case Builtin::BI__builtin___clear_cache: { Value *Begin = EmitScalarExpr(E->getArg(0)); @@ -923,7 +923,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__builtin_unwind_init: { Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init); - return RValue::get(Builder.CreateCall(F, {})); + return RValue::get(Builder.CreateCall(F)); } case Builtin::BI__builtin_extend_pointer: { // Extends a pointer to the size of an _Unwind_Word, which is @@ -962,7 +962,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // Store the stack pointer to the setjmp buffer. Value *StackAddr = - Builder.CreateCall(CGM.getIntrinsic(Intrinsic::stacksave), {}); + Builder.CreateCall(CGM.getIntrinsic(Intrinsic::stacksave)); Value *StackSaveSlot = Builder.CreateGEP(Buf, ConstantInt::get(Int32Ty, 2)); Builder.CreateStore(StackAddr, StackSaveSlot); @@ -3399,7 +3399,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, : InlineAsm::get(FTy, ".inst 0x" + utohexstr(ZExtValue), "", /*SideEffects=*/true); - return Builder.CreateCall(Emit, {}); + return Builder.CreateCall(Emit); } if (BuiltinID == ARM::BI__builtin_arm_dbg) { @@ -3543,7 +3543,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, if (BuiltinID == ARM::BI__builtin_arm_clrex) { Function *F = CGM.getIntrinsic(Intrinsic::arm_clrex); - return Builder.CreateCall(F, {}); + return Builder.CreateCall(F); } // CRC32 @@ -4339,7 +4339,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, if (BuiltinID == AArch64::BI__builtin_arm_clrex) { Function *F = CGM.getIntrinsic(Intrinsic::aarch64_clrex); - return Builder.CreateCall(F, {}); + return Builder.CreateCall(F); } // CRC32 @@ -6375,7 +6375,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, break; } - Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID), {}); + Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID)); Builder.CreateStore(Builder.CreateExtractValue(Call, 0), Ops[0]); return Builder.CreateExtractValue(Call, 1); } @@ -6633,14 +6633,104 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, llvm::Function *F = CGM.getIntrinsic(ID); return Builder.CreateCall(F, Ops, ""); } + // Square root + case PPC::BI__builtin_vsx_xvsqrtsp: + case PPC::BI__builtin_vsx_xvsqrtdp: { + llvm::Type *ResultType = ConvertType(E->getType()); + Value *X = EmitScalarExpr(E->getArg(0)); + ID = Intrinsic::sqrt; + llvm::Function *F = CGM.getIntrinsic(ID, ResultType); + return Builder.CreateCall(F, X); + } + // Count leading zeros + case PPC::BI__builtin_altivec_vclzb: + case PPC::BI__builtin_altivec_vclzh: + case PPC::BI__builtin_altivec_vclzw: + case PPC::BI__builtin_altivec_vclzd: { + llvm::Type *ResultType = ConvertType(E->getType()); + Value *X = EmitScalarExpr(E->getArg(0)); + Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false); + Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ResultType); + return Builder.CreateCall(F, {X, Undef}); + } + // Copy sign + case PPC::BI__builtin_vsx_xvcpsgnsp: + case PPC::BI__builtin_vsx_xvcpsgndp: { + llvm::Type *ResultType = ConvertType(E->getType()); + Value *X = EmitScalarExpr(E->getArg(0)); + Value *Y = EmitScalarExpr(E->getArg(1)); + ID = Intrinsic::copysign; + llvm::Function *F = CGM.getIntrinsic(ID, ResultType); + return Builder.CreateCall(F, {X, Y}); + } + // Rounding/truncation case PPC::BI__builtin_vsx_xvrspip: case PPC::BI__builtin_vsx_xvrdpip: + case PPC::BI__builtin_vsx_xvrdpim: + case PPC::BI__builtin_vsx_xvrspim: + case PPC::BI__builtin_vsx_xvrdpi: + case PPC::BI__builtin_vsx_xvrspi: + case PPC::BI__builtin_vsx_xvrdpic: + case PPC::BI__builtin_vsx_xvrspic: + case PPC::BI__builtin_vsx_xvrdpiz: + case PPC::BI__builtin_vsx_xvrspiz: { llvm::Type *ResultType = ConvertType(E->getType()); Value *X = EmitScalarExpr(E->getArg(0)); - ID = Intrinsic::ceil; + if (BuiltinID == PPC::BI__builtin_vsx_xvrdpim || + BuiltinID == PPC::BI__builtin_vsx_xvrspim) + ID = Intrinsic::floor; + else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpi || + BuiltinID == PPC::BI__builtin_vsx_xvrspi) + ID = Intrinsic::round; + else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpic || + BuiltinID == PPC::BI__builtin_vsx_xvrspic) + ID = Intrinsic::nearbyint; + else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpip || + BuiltinID == PPC::BI__builtin_vsx_xvrspip) + ID = Intrinsic::ceil; + else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpiz || + BuiltinID == PPC::BI__builtin_vsx_xvrspiz) + ID = Intrinsic::trunc; llvm::Function *F = CGM.getIntrinsic(ID, ResultType); return Builder.CreateCall(F, X); } + // FMA variations + case PPC::BI__builtin_vsx_xvmaddadp: + case PPC::BI__builtin_vsx_xvmaddasp: + case PPC::BI__builtin_vsx_xvnmaddadp: + case PPC::BI__builtin_vsx_xvnmaddasp: + case PPC::BI__builtin_vsx_xvmsubadp: + case PPC::BI__builtin_vsx_xvmsubasp: + case PPC::BI__builtin_vsx_xvnmsubadp: + case PPC::BI__builtin_vsx_xvnmsubasp: { + llvm::Type *ResultType = ConvertType(E->getType()); + Value *X = EmitScalarExpr(E->getArg(0)); + Value *Y = EmitScalarExpr(E->getArg(1)); + Value *Z = EmitScalarExpr(E->getArg(2)); + Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType); + llvm::Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType); + switch (BuiltinID) { + case PPC::BI__builtin_vsx_xvmaddadp: + case PPC::BI__builtin_vsx_xvmaddasp: + return Builder.CreateCall(F, {X, Y, Z}); + case PPC::BI__builtin_vsx_xvnmaddadp: + case PPC::BI__builtin_vsx_xvnmaddasp: + return Builder.CreateFSub(Zero, + Builder.CreateCall(F, {X, Y, Z}), "sub"); + case PPC::BI__builtin_vsx_xvmsubadp: + case PPC::BI__builtin_vsx_xvmsubasp: + return Builder.CreateCall(F, + {X, Y, Builder.CreateFSub(Zero, Z, "sub")}); + case PPC::BI__builtin_vsx_xvnmsubadp: + case PPC::BI__builtin_vsx_xvnmsubasp: + Value *FsubRes = + Builder.CreateCall(F, {X, Y, Builder.CreateFSub(Zero, Z, "sub")}); + return Builder.CreateFSub(Zero, FsubRes, "sub"); + } + llvm_unreachable("Unknown FMA operation"); + return nullptr; // Suppress no-return warning + } + } } // Emit an intrinsic that has 1 float or double. diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 0535c05da5d5..3e4d7f323d46 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -912,20 +912,21 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val, /// CreateCoercedLoad - Create a load from \arg SrcPtr interpreted as -/// a pointer to an object of type \arg Ty. +/// a pointer to an object of type \arg Ty, known to be aligned to +/// \arg SrcAlign bytes. /// /// This safely handles the case when the src type is smaller than the /// destination type; in this situation the values of bits which not /// present in the src are undefined. static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, - llvm::Type *Ty, + llvm::Type *Ty, CharUnits SrcAlign, CodeGenFunction &CGF) { llvm::Type *SrcTy = cast<llvm::PointerType>(SrcPtr->getType())->getElementType(); // If SrcTy and Ty are the same, just do a load. if (SrcTy == Ty) - return CGF.Builder.CreateLoad(SrcPtr); + return CGF.Builder.CreateAlignedLoad(SrcPtr, SrcAlign.getQuantity()); uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty); @@ -940,7 +941,8 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, // extension or truncation to the desired type. if ((isa<llvm::IntegerType>(Ty) || isa<llvm::PointerType>(Ty)) && (isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy))) { - llvm::LoadInst *Load = CGF.Builder.CreateLoad(SrcPtr); + llvm::LoadInst *Load = + CGF.Builder.CreateAlignedLoad(SrcPtr, SrcAlign.getQuantity()); return CoerceIntOrPtrToIntOrPtr(Load, Ty, CGF); } @@ -954,23 +956,20 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, // to that information. llvm::Value *Casted = CGF.Builder.CreateBitCast(SrcPtr, llvm::PointerType::getUnqual(Ty)); - llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted); - // FIXME: Use better alignment / avoid requiring aligned load. - Load->setAlignment(1); - return Load; + return CGF.Builder.CreateAlignedLoad(Casted, SrcAlign.getQuantity()); } // Otherwise do coercion through memory. This is stupid, but // simple. - llvm::Value *Tmp = CGF.CreateTempAlloca(Ty); + llvm::AllocaInst *Tmp = CGF.CreateTempAlloca(Ty); + Tmp->setAlignment(SrcAlign.getQuantity()); llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy(); llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy); llvm::Value *SrcCasted = CGF.Builder.CreateBitCast(SrcPtr, I8PtrTy); - // FIXME: Use better alignment. CGF.Builder.CreateMemCpy(Casted, SrcCasted, llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize), - 1, false); - return CGF.Builder.CreateLoad(Tmp); + SrcAlign.getQuantity(), false); + return CGF.Builder.CreateAlignedLoad(Tmp, SrcAlign.getQuantity()); } // Function to store a first-class aggregate into memory. We prefer to @@ -979,39 +978,45 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, // FIXME: Do we need to recurse here? static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val, llvm::Value *DestPtr, bool DestIsVolatile, - bool LowAlignment) { + CharUnits DestAlign) { // Prefer scalar stores to first-class aggregate stores. if (llvm::StructType *STy = dyn_cast<llvm::StructType>(Val->getType())) { + const llvm::StructLayout *Layout = + CGF.CGM.getDataLayout().getStructLayout(STy); + for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(STy, DestPtr, 0, i); llvm::Value *Elt = CGF.Builder.CreateExtractValue(Val, i); - llvm::StoreInst *SI = CGF.Builder.CreateStore(Elt, EltPtr, - DestIsVolatile); - if (LowAlignment) - SI->setAlignment(1); + uint64_t EltOffset = Layout->getElementOffset(i); + CharUnits EltAlign = + DestAlign.alignmentAtOffset(CharUnits::fromQuantity(EltOffset)); + CGF.Builder.CreateAlignedStore(Elt, EltPtr, EltAlign.getQuantity(), + DestIsVolatile); } } else { - llvm::StoreInst *SI = CGF.Builder.CreateStore(Val, DestPtr, DestIsVolatile); - if (LowAlignment) - SI->setAlignment(1); + CGF.Builder.CreateAlignedStore(Val, DestPtr, DestAlign.getQuantity(), + DestIsVolatile); } } /// CreateCoercedStore - Create a store to \arg DstPtr from \arg Src, -/// where the source and destination may have different types. +/// where the source and destination may have different types. The +/// destination is known to be aligned to \arg DstAlign bytes. /// /// This safely handles the case when the src type is larger than the /// destination type; the upper bits of the src will be lost. static void CreateCoercedStore(llvm::Value *Src, llvm::Value *DstPtr, bool DstIsVolatile, + CharUnits DstAlign, CodeGenFunction &CGF) { llvm::Type *SrcTy = Src->getType(); llvm::Type *DstTy = cast<llvm::PointerType>(DstPtr->getType())->getElementType(); if (SrcTy == DstTy) { - CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile); + CGF.Builder.CreateAlignedStore(Src, DstPtr, DstAlign.getQuantity(), + DstIsVolatile); return; } @@ -1027,7 +1032,8 @@ static void CreateCoercedStore(llvm::Value *Src, if ((isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy)) && (isa<llvm::IntegerType>(DstTy) || isa<llvm::PointerType>(DstTy))) { Src = CoerceIntOrPtrToIntOrPtr(Src, DstTy, CGF); - CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile); + CGF.Builder.CreateAlignedStore(Src, DstPtr, DstAlign.getQuantity(), + DstIsVolatile); return; } @@ -1037,8 +1043,7 @@ static void CreateCoercedStore(llvm::Value *Src, if (SrcSize <= DstSize) { llvm::Value *Casted = CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy)); - // FIXME: Use better alignment / avoid requiring aligned store. - BuildAggStore(CGF, Src, Casted, DstIsVolatile, true); + BuildAggStore(CGF, Src, Casted, DstIsVolatile, DstAlign); } else { // Otherwise do coercion through memory. This is stupid, but // simple. @@ -1049,15 +1054,15 @@ static void CreateCoercedStore(llvm::Value *Src, // // FIXME: Assert that we aren't truncating non-padding bits when have access // to that information. - llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy); - CGF.Builder.CreateStore(Src, Tmp); + llvm::AllocaInst *Tmp = CGF.CreateTempAlloca(SrcTy); + Tmp->setAlignment(DstAlign.getQuantity()); + CGF.Builder.CreateAlignedStore(Src, Tmp, DstAlign.getQuantity()); llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy(); llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy); llvm::Value *DstCasted = CGF.Builder.CreateBitCast(DstPtr, I8PtrTy); - // FIXME: Use better alignment. CGF.Builder.CreateMemCpy(DstCasted, Casted, llvm::ConstantInt::get(CGF.IntPtrTy, DstSize), - 1, false); + DstAlign.getQuantity(), false); } } @@ -1506,7 +1511,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl); if (FD) { - if (const TargetAttr *TD = FD->getAttr<TargetAttr>()) { + if (const auto *TD = FD->getAttr<TargetAttr>()) { StringRef FeaturesStr = TD->getFeatures(); SmallVector<StringRef, 1> AttrFeatures; FeaturesStr.split(AttrFeatures, ","); @@ -1514,9 +1519,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, // Grab the various features and prepend a "+" to turn on the feature to // the backend and add them to our existing set of features. for (auto &Feature : AttrFeatures) { + // Go ahead and trim whitespace rather than either erroring or + // accepting it weirdly. + Feature = Feature.trim(); + // While we're here iterating check for a different target cpu. if (Feature.startswith("arch=")) - TargetCPU = Feature.split("=").second; + TargetCPU = Feature.split("=").second.trim(); else if (Feature.startswith("tune=")) // We don't support cpu tuning this way currently. ; @@ -1992,6 +2001,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, Alloca->setAlignment(AlignmentToUse); llvm::Value *V = Alloca; llvm::Value *Ptr = V; // Pointer to store into. + CharUnits PtrAlign = CharUnits::fromQuantity(AlignmentToUse); // If the value is offset in memory, apply the offset now. if (unsigned Offs = ArgI.getDirectOffset()) { @@ -1999,6 +2009,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, Ptr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), Ptr, Offs); Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(ArgI.getCoerceToType())); + PtrAlign = PtrAlign.alignmentAtOffset(CharUnits::fromQuantity(Offs)); } // Fast-isel and the optimizer generally like scalar values better than @@ -2043,7 +2054,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, assert(NumIRArgs == 1); auto AI = FnArgs[FirstIRArg]; AI->setName(Arg->getName() + ".coerce"); - CreateCoercedStore(AI, Ptr, /*DestIsVolatile=*/false, *this); + CreateCoercedStore(AI, Ptr, /*DestIsVolatile=*/false, PtrAlign, *this); } @@ -2411,15 +2422,17 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, } } else { llvm::Value *V = ReturnValue; + CharUnits Align = getContext().getTypeAlignInChars(RetTy); // If the value is offset in memory, apply the offset now. if (unsigned Offs = RetAI.getDirectOffset()) { V = Builder.CreateBitCast(V, Builder.getInt8PtrTy()); V = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), V, Offs); V = Builder.CreateBitCast(V, llvm::PointerType::getUnqual(RetAI.getCoerceToType())); + Align = Align.alignmentAtOffset(CharUnits::fromQuantity(Offs)); } - RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this); + RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), Align, *this); } // In ARC, end functions that return a retainable type with a call @@ -3282,12 +3295,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // FIXME: Avoid the conversion through memory if possible. llvm::Value *SrcPtr; + CharUnits SrcAlign; if (RV.isScalar() || RV.isComplex()) { SrcPtr = CreateMemTemp(I->Ty, "coerce"); + SrcAlign = TypeAlign; LValue SrcLV = MakeAddrLValue(SrcPtr, I->Ty, TypeAlign); EmitInitStoreOfNonAggregate(*this, RV, SrcLV); - } else + } else { SrcPtr = RV.getAggregateAddr(); + // This alignment is guaranteed by EmitCallArg. + SrcAlign = TypeAlign; + } // If the value is offset in memory, apply the offset now. if (unsigned Offs = ArgInfo.getDirectOffset()) { @@ -3295,7 +3313,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, SrcPtr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), SrcPtr, Offs); SrcPtr = Builder.CreateBitCast(SrcPtr, llvm::PointerType::getUnqual(ArgInfo.getCoerceToType())); - + SrcAlign = SrcAlign.alignmentAtOffset(CharUnits::fromQuantity(Offs)); } // Fast-isel and the optimizer generally like scalar values better than @@ -3334,7 +3352,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // In the simple case, just pass the coerced loaded value. assert(NumIRArgs == 1); IRCallArgs[FirstIRArg] = - CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(), *this); + CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(), + SrcAlign, *this); } break; @@ -3531,12 +3550,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case TEK_Aggregate: { llvm::Value *DestPtr = ReturnValue.getValue(); bool DestIsVolatile = ReturnValue.isVolatile(); + CharUnits DestAlign = getContext().getTypeAlignInChars(RetTy); if (!DestPtr) { DestPtr = CreateMemTemp(RetTy, "agg.tmp"); DestIsVolatile = false; } - BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false); + BuildAggStore(*this, CI, DestPtr, DestIsVolatile, DestAlign); return RValue::getAggregate(DestPtr); } case TEK_Scalar: { @@ -3553,6 +3573,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *DestPtr = ReturnValue.getValue(); bool DestIsVolatile = ReturnValue.isVolatile(); + CharUnits DestAlign = getContext().getTypeAlignInChars(RetTy); if (!DestPtr) { DestPtr = CreateMemTemp(RetTy, "coerce"); @@ -3561,14 +3582,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If the value is offset in memory, apply the offset now. llvm::Value *StorePtr = DestPtr; + CharUnits StoreAlign = DestAlign; if (unsigned Offs = RetAI.getDirectOffset()) { StorePtr = Builder.CreateBitCast(StorePtr, Builder.getInt8PtrTy()); StorePtr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), StorePtr, Offs); StorePtr = Builder.CreateBitCast(StorePtr, llvm::PointerType::getUnqual(RetAI.getCoerceToType())); + StoreAlign = + StoreAlign.alignmentAtOffset(CharUnits::fromQuantity(Offs)); } - CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this); + CreateCoercedStore(CI, StorePtr, DestIsVolatile, StoreAlign, *this); return convertTempToRValue(DestPtr, RetTy, SourceLocation()); } diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 62df9820a6c3..c49f182c21d8 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -554,6 +554,20 @@ static bool isMemcpyEquivalentSpecialMember(const CXXMethodDecl *D) { return false; } +static void EmitLValueForAnyFieldInitialization(CodeGenFunction &CGF, + CXXCtorInitializer *MemberInit, + LValue &LHS) { + FieldDecl *Field = MemberInit->getAnyMember(); + if (MemberInit->isIndirectMemberInitializer()) { + // If we are initializing an anonymous union field, drill down to the field. + IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember(); + for (const auto *I : IndirectField->chain()) + LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I)); + } else { + LHS = CGF.EmitLValueForFieldInitialization(LHS, Field); + } +} + static void EmitMemberInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXCtorInitializer *MemberInit, @@ -572,16 +586,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl); LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy); - if (MemberInit->isIndirectMemberInitializer()) { - // If we are initializing an anonymous union field, drill down to - // the field. - IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember(); - for (const auto *I : IndirectField->chain()) - LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I)); - FieldType = MemberInit->getIndirectMember()->getAnonField()->getType(); - } else { - LHS = CGF.EmitLValueForFieldInitialization(LHS, Field); - } + EmitLValueForAnyFieldInitialization(CGF, MemberInit, LHS); // Special case: if we are in a copy or move constructor, and we are copying // an array of PODs or classes with trivial copy constructors, ignore the @@ -606,6 +611,11 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, // Copy the aggregate. CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType, LHS.isVolatileQualified()); + // Ensure that we destroy the objects if an exception is thrown later in + // the constructor. + QualType::DestructionKind dtorKind = FieldType.isDestructedType(); + if (CGF.needsEHCleanup(dtorKind)) + CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType); return; } } @@ -906,32 +916,18 @@ namespace { return; } - CharUnits Alignment; - uint64_t FirstByteOffset; if (FirstField->isBitField()) { const CGRecordLayout &RL = CGF.getTypes().getCGRecordLayout(FirstField->getParent()); const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField); - Alignment = CharUnits::fromQuantity(BFInfo.StorageAlignment); // FirstFieldOffset is not appropriate for bitfields, - // it won't tell us what the storage offset should be and thus might not - // be properly aligned. - // - // Instead calculate the storage offset using the offset of the field in - // the struct type. - const llvm::DataLayout &DL = CGF.CGM.getDataLayout(); - FirstByteOffset = - DL.getStructLayout(RL.getLLVMType()) - ->getElementOffsetInBits(RL.getLLVMFieldNo(FirstField)); + // we need to use the storage offset instead. + FirstByteOffset = CGF.getContext().toBits(BFInfo.StorageOffset); } else { - Alignment = CGF.getContext().getDeclAlign(FirstField); FirstByteOffset = FirstFieldOffset; } - assert((CGF.getContext().toCharUnitsFromBits(FirstByteOffset) % - Alignment) == 0 && "Bad field alignment."); - CharUnits MemcpySize = getMemcpySize(FirstByteOffset); QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl); llvm::Value *ThisPtr = CGF.LoadCXXThis(); @@ -941,6 +937,9 @@ namespace { LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy); LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField); + CharUnits Offset = CGF.getContext().toCharUnitsFromBits(FirstByteOffset); + CharUnits Alignment = DestLV.getAlignment().alignmentAtOffset(Offset); + emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddr() : Dest.getAddress(), Src.isBitField() ? Src.getBitFieldAddr() : Src.getAddress(), MemcpySize, Alignment); @@ -1078,6 +1077,7 @@ namespace { CopyingValueRepresentation CVR(CGF); EmitMemberInitializer(CGF, ConstructorDecl->getParent(), AggregatedInits[0], ConstructorDecl, Args); + AggregatedInits.clear(); } reset(); return; @@ -1094,10 +1094,14 @@ namespace { LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy); for (unsigned i = 0; i < AggregatedInits.size(); ++i) { - QualType FieldType = AggregatedInits[i]->getMember()->getType(); + CXXCtorInitializer *MemberInit = AggregatedInits[i]; + QualType FieldType = MemberInit->getAnyMember()->getType(); QualType::DestructionKind dtorKind = FieldType.isDestructedType(); - if (CGF.needsEHCleanup(dtorKind)) - CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType); + if (!CGF.needsEHCleanup(dtorKind)) + continue; + LValue FieldLHS = LHS; + EmitLValueForAnyFieldInitialization(CGF, MemberInit, FieldLHS); + CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(), FieldType); } } @@ -1363,6 +1367,25 @@ static bool CanSkipVTablePointerInitialization(ASTContext &Context, return true; } +// Generates function call for handling object poisoning, passing in +// references to 'this' and its size as arguments. +static void EmitDtorSanitizerCallback(CodeGenFunction &CGF, + const CXXDestructorDecl *Dtor) { + const ASTRecordLayout &Layout = + CGF.getContext().getASTRecordLayout(Dtor->getParent()); + + llvm::Value *Args[] = { + CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.VoidPtrTy), + llvm::ConstantInt::get(CGF.SizeTy, Layout.getSize().getQuantity())}; + llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy}; + + llvm::FunctionType *FnType = + llvm::FunctionType::get(CGF.VoidTy, ArgTypes, false); + llvm::Value *Fn = + CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback"); + CGF.EmitNounwindRuntimeCall(Fn, Args); +} + /// EmitDestructorBody - Emits the body of the current destructor. void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl()); @@ -1450,6 +1473,10 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // Exit the try if applicable. if (isTryBody) ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true); + + // Insert memory-poisoning instrumentation. + if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor) + EmitDtorSanitizerCallback(*this, Dtor); } void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) { @@ -2202,8 +2229,7 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable, CFITypeCheckKind TCK, SourceLocation Loc) { - // FIXME: Add blacklisting scheme. - if (RD->isInStdNamespace()) + if (CGM.IsCFIBlacklistedRecord(RD)) return; SanitizerScope SanScope(this); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 8c4b4b3d0617..93a2287b1e01 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -106,8 +106,6 @@ ApplyDebugLocation::~ApplyDebugLocation() { CGF.Builder.SetCurrentDebugLocation(std::move(OriginalLocation)); } -/// ArtificialLocation - An RAII object that temporarily switches to -/// an artificial debug location that has a valid scope, but no line void CGDebugInfo::setLocation(SourceLocation Loc) { // If the new location isn't valid return. if (Loc.isInvalid()) @@ -140,7 +138,6 @@ void CGDebugInfo::setLocation(SourceLocation Loc) { } } -/// getContextDescriptor - Get context info for the decl. llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context) { if (!Context) return TheCU; @@ -162,9 +159,6 @@ llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context) { return TheCU; } -/// getFunctionName - Get function name for the given FunctionDecl. If the -/// name is constructed on demand (e.g. C++ destructor) then the name -/// is stored on the side. StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { assert(FD && "Invalid FunctionDecl!"); IdentifierInfo *FII = FD->getIdentifier(); @@ -220,13 +214,10 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { return internString(OS.str()); } -/// getSelectorName - Return selector name. This is used for debugging -/// info. StringRef CGDebugInfo::getSelectorName(Selector S) { return internString(S.getAsString()); } -/// getClassName - Get class name including template argument list. StringRef CGDebugInfo::getClassName(const RecordDecl *RD) { // quick optimization to avoid having to intern strings that are already // stored reliably elsewhere @@ -244,7 +235,6 @@ StringRef CGDebugInfo::getClassName(const RecordDecl *RD) { return internString(Name); } -/// getOrCreateFile - Get the file debug info descriptor for the input location. llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { if (!Loc.isValid()) // If Location is not valid then use main input file. @@ -274,13 +264,10 @@ llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { return F; } -/// getOrCreateMainFile - Get the file info for main compile unit. llvm::DIFile *CGDebugInfo::getOrCreateMainFile() { return DBuilder.createFile(TheCU->getFilename(), TheCU->getDirectory()); } -/// getLineNumber - Get line number for the location. If location is invalid -/// then use current location. unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { if (Loc.isInvalid() && CurLoc.isInvalid()) return 0; @@ -289,7 +276,6 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { return PLoc.isValid() ? PLoc.getLine() : 0; } -/// getColumnNumber - Get column number for the location. unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) { // We may not want column information at all. if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo) @@ -314,7 +300,6 @@ StringRef CGDebugInfo::getCurrentDirname() { return CWDName = internString(CWD); } -/// CreateCompileUnit - Create new compile unit. void CGDebugInfo::CreateCompileUnit() { // Should we be asking the SourceManager for the main file name, instead of @@ -385,8 +370,6 @@ void CGDebugInfo::CreateCompileUnit() { DebugKind != CodeGenOptions::LocTrackingOnly); } -/// CreateType - Get the Basic type from the cache or create a new -/// one if necessary. llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { llvm::dwarf::TypeKind Encoding; StringRef BTName; @@ -537,8 +520,6 @@ llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) { return DBuilder.createBasicType("complex", Size, Align, Encoding); } -/// CreateCVRType - Get the qualified type from the cache or create -/// a new one if necessary. llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile *Unit) { QualifierCollector Qc; @@ -627,6 +608,7 @@ static SmallString<256> getUniqueTagTypeName(const TagType *Ty, return FullName; } +/// \return the approproate DWARF tag for a composite type. static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) { llvm::dwarf::Tag Tag; if (RD->isStruct() || RD->isInterface()) @@ -642,7 +624,6 @@ static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) { return Tag; } -// Creates a forward declaration for a RecordDecl in the given context. llvm::DICompositeType * CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty, llvm::DIScope *Ctx) { @@ -705,9 +686,6 @@ llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIFile *Unit) { - if (BlockLiteralGeneric) - return BlockLiteralGeneric; - SmallVector<llvm::Metadata *, 8> EltTys; QualType FType; uint64_t FieldSize, FieldOffset; @@ -723,10 +701,10 @@ llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.clear(); unsigned Flags = llvm::DINode::FlagAppleBlock; - unsigned LineNo = getLineNumber(CurLoc); + unsigned LineNo = 0; auto *EltTy = - DBuilder.createStructType(Unit, "__block_descriptor", Unit, LineNo, + DBuilder.createStructType(Unit, "__block_descriptor", nullptr, LineNo, FieldOffset, 0, Flags, nullptr, Elements); // Bit size, align and offset of the type. @@ -746,19 +724,22 @@ llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty, FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldSize = CGM.getContext().getTypeSize(Ty); FieldAlign = CGM.getContext().getTypeAlign(Ty); - EltTys.push_back(DBuilder.createMemberType(Unit, "__descriptor", Unit, LineNo, + EltTys.push_back(DBuilder.createMemberType(Unit, "__descriptor", nullptr, LineNo, FieldSize, FieldAlign, FieldOffset, 0, DescTy)); FieldOffset += FieldSize; Elements = DBuilder.getOrCreateArray(EltTys); + // The __block_literal_generic structs are marked with a special + // DW_AT_APPLE_BLOCK attribute and are an implementation detail only + // the debugger needs to know about. To allow type uniquing, emit + // them without a name or a location. EltTy = - DBuilder.createStructType(Unit, "__block_literal_generic", Unit, LineNo, + DBuilder.createStructType(Unit, "", nullptr, LineNo, FieldOffset, 0, Flags, nullptr, Elements); - BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size); - return BlockLiteralGeneric; + return DBuilder.createPointerType(EltTy, Size); } llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, @@ -871,7 +852,6 @@ llvm::DIType *CGDebugInfo::createFieldType( AlignInBits, offsetInBits, flags, debugType); } -/// CollectRecordLambdaFields - Helper for CollectRecordFields. void CGDebugInfo::CollectRecordLambdaFields( const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &elements, llvm::DIType *RecordTy) { @@ -916,7 +896,6 @@ void CGDebugInfo::CollectRecordLambdaFields( } } -/// Helper for CollectRecordFields. llvm::DIDerivedType * CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, const RecordDecl *RD) { @@ -946,7 +925,6 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, return GV; } -/// CollectRecordNormalField - Helper for CollectRecordFields. void CGDebugInfo::CollectRecordNormalField( const FieldDecl *field, uint64_t OffsetInBits, llvm::DIFile *tunit, SmallVectorImpl<llvm::Metadata *> &elements, llvm::DIType *RecordTy, @@ -971,8 +949,6 @@ void CGDebugInfo::CollectRecordNormalField( elements.push_back(fieldType); } -/// CollectRecordFields - A helper function to collect debug info for -/// record fields. This is used while creating debug info entry for a Record. void CGDebugInfo::CollectRecordFields( const RecordDecl *record, llvm::DIFile *tunit, SmallVectorImpl<llvm::Metadata *> &elements, @@ -1011,9 +987,6 @@ void CGDebugInfo::CollectRecordFields( } } -/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This -/// function type is not updated to include implicit "this" pointer. Use this -/// routine to get a method type which includes "this" pointer. llvm::DISubroutineType * CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile *Unit) { @@ -1088,8 +1061,6 @@ static bool isFunctionLocalClass(const CXXRecordDecl *RD) { return false; } -/// CreateCXXMemberFunction - A helper function to create a subprogram for -/// a single member function GlobalDecl. llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) { bool IsCtorOrDtor = @@ -1165,9 +1136,6 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( return SP; } -/// CollectCXXMemberFunctions - A helper function to collect debug info for -/// C++ member functions. This is used while creating debug info entry for -/// a Record. void CGDebugInfo::CollectCXXMemberFunctions( const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy) { @@ -1206,9 +1174,6 @@ void CGDebugInfo::CollectCXXMemberFunctions( } } -/// CollectCXXBases - A helper function to collect debug info for -/// C++ base classes. This is used while creating debug info entry for -/// a Record. void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy) { @@ -1246,7 +1211,6 @@ void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit, } } -/// CollectTemplateParams - A helper function to collect template parameters. llvm::DINodeArray CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, ArrayRef<TemplateArgument> TAList, @@ -1351,8 +1315,6 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, return DBuilder.getOrCreateArray(TemplateParams); } -/// CollectFunctionTemplateParams - A helper function to collect debug -/// info for function template parameters. llvm::DINodeArray CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile *Unit) { @@ -1367,8 +1329,6 @@ CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, return llvm::DINodeArray(); } -/// CollectCXXTemplateParams - A helper function to collect debug info for -/// template parameters. llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams( const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile *Unit) { // Always get the full list of parameters, not just the ones from @@ -1379,7 +1339,6 @@ llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams( return CollectTemplateParams(TPList, TAList.asArray(), Unit); } -/// getOrCreateVTablePtrType - Return debug info descriptor for vtable. llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { if (VTablePtrType) return VTablePtrType; @@ -1397,14 +1356,11 @@ llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { return VTablePtrType; } -/// getVTableName - Get vtable name for the given Class. StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { // Copy the gdb compatible name on the side and use its reference. return internString("_vptr$", RD->getNameAsString()); } -/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate -/// debug info entry in EltTys vector. void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl<llvm::Metadata *> &EltTys) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); @@ -1424,7 +1380,6 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, EltTys.push_back(VPTR); } -/// getOrCreateRecordType - Emit record type's standalone debug info. llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy, SourceLocation Loc) { assert(DebugKind >= CodeGenOptions::LimitedDebugInfo); @@ -1432,8 +1387,6 @@ llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy, return T; } -/// getOrCreateInterfaceType - Emit an objective c interface type standalone -/// debug info. llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D, SourceLocation Loc) { assert(DebugKind >= CodeGenOptions::LimitedDebugInfo); @@ -1531,7 +1484,6 @@ static bool shouldOmitDefinition(CodeGenOptions::DebugInfoKind DebugKind, return false; } -/// CreateType - get structure or union type. llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) { RecordDecl *RD = Ty->getDecl(); llvm::DIType *T = cast_or_null<llvm::DIType>(getTypeOrNull(QualType(Ty, 0))); @@ -1605,7 +1557,6 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) { return FwdDecl; } -/// CreateType - get objective-c object type. llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectType *Ty, llvm::DIFile *Unit) { // Ignore protocols. @@ -1636,7 +1587,6 @@ static bool hasDefaultSetterName(const ObjCPropertyDecl *PD, Setter->getDeclName().getObjCSelector().getNameForSlot(0); } -/// CreateType - get objective-c interface type. llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DIFile *Unit) { ObjCInterfaceDecl *ID = Ty->getDecl(); @@ -1956,7 +1906,6 @@ llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) { return getOrCreateType(Ty->getValueType(), U); } -/// CreateEnumType - get enumeration type. llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); uint64_t Size = 0; @@ -2076,8 +2025,6 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { } while (true); } -/// getType - Get the type from the cache or return null type if it doesn't -/// exist. llvm::DIType *CGDebugInfo::getTypeOrNull(QualType Ty) { // Unwrap the type as needed for debug information. @@ -2104,8 +2051,6 @@ void CGDebugInfo::completeTemplateDefinition( RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr()); } -/// getOrCreateType - Get the type from the cache or create a new -/// one if necessary. llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { if (Ty.isNull()) return nullptr; @@ -2126,8 +2071,6 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { return Res; } -/// Currently the checksum of an interface includes the number of -/// ivars and property accessors. unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl *ID) { // The assumption is that the number of ivars can only increase // monotonically, so it is safe to just use their current number as @@ -2152,7 +2095,6 @@ ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) { } } -/// CreateTypeNode - Create a new debug type node. llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { // Handle qualifiers, which recursively handles what they refer to. if (Ty.hasLocalQualifiers()) @@ -2233,8 +2175,6 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { llvm_unreachable("type should have been unwrapped!"); } -/// getOrCreateLimitedType - Get the type from the cache or create a new -/// limited type if necessary. llvm::DIType *CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile *Unit) { QualType QTy(Ty, 0); @@ -2328,7 +2268,6 @@ void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD, DBuilder.replaceVTableHolder(RealDecl, ContainingType); } -/// CreateMemberType - Create new member and increase Offset by FType's size. llvm::DIType *CGDebugInfo::CreateMemberType(llvm::DIFile *Unit, QualType FType, StringRef Name, uint64_t *Offset) { llvm::DIType *FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); @@ -2493,8 +2432,6 @@ llvm::DINode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) { return nullptr; } -/// getFunctionDeclaration - Return debug info descriptor to describe method -/// declaration for the given method definition. llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) { if (!D || DebugKind <= CodeGenOptions::DebugLineTablesOnly) return nullptr; @@ -2591,7 +2528,6 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D, return cast<llvm::DISubroutineType>(getOrCreateType(FnType, F)); } -/// EmitFunctionStart - Constructs the debug code for entering a function. void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, SourceLocation ScopeLoc, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { @@ -2667,9 +2603,6 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, RegionMap[D].reset(SP); } -/// EmitLocation - Emit metadata to indicate a change in line/column -/// information in the source file. If the location is invalid, the -/// previous location will be reused. void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { // Update our current location setLocation(Loc); @@ -2682,8 +2615,6 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope)); } -/// CreateLexicalBlock - Creates a new lexical block node and pushes it on -/// the stack. void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { llvm::MDNode *Back = nullptr; if (!LexicalBlockStack.empty()) @@ -2693,8 +2624,6 @@ void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { getColumnNumber(CurLoc))); } -/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative -/// region - beginning of a DW_TAG_lexical_block. void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) { // Set our current location. @@ -2711,8 +2640,6 @@ void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, CreateLexicalBlock(Loc); } -/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative -/// region - end of a DW_TAG_lexical_block. void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) { assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); @@ -2726,7 +2653,6 @@ void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, LexicalBlockStack.pop_back(); } -/// EmitFunctionEnd - Constructs the debug code for exiting a function. void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); unsigned RCount = FnBeginRegionCount.back(); @@ -2741,8 +2667,6 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { FnBeginRegionCount.pop_back(); } -// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. -// See BuildByRefType. llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, uint64_t *XOffset) { @@ -2816,7 +2740,6 @@ llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, nullptr, Elements); } -/// EmitDeclare - Emit local variable declaration debug info. void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::Tag Tag, llvm::Value *Storage, unsigned ArgNo, CGBuilderTy &Builder) { @@ -2944,12 +2867,6 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder); } -/// Look up the completed type for a self pointer in the TypeCache and -/// create a copy of it with the ObjectPointer and Artificial flags -/// set. If the type is not cached, a new one is created. This should -/// never happen though, since creating a type for the implicit self -/// argument implies that we already parsed the interface definition -/// and the ivar declarations in the implementation. llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy, llvm::DIType *Ty) { llvm::DIType *CachedTy = getTypeOrNull(QualTy); @@ -3027,8 +2944,6 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( Builder.GetInsertBlock()); } -/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument -/// variable declaration. void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder) { @@ -3192,8 +3107,6 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, Builder.GetInsertBlock()); } -/// If D is an out-of-class definition of a static data member of a class, find -/// its corresponding in-class declaration. llvm::DIDerivedType * CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) { if (!D->isStaticDataMember()) @@ -3213,9 +3126,6 @@ CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) { return CreateRecordStaticField(D, Ctxt, cast<RecordDecl>(DC)); } -/// Recursively collect all of the member fields of a global anonymous decl and -/// create static variables for them. The first time this is called it needs -/// to be on a union and then from there we can have additional unnamed fields. llvm::DIGlobalVariable *CGDebugInfo::CollectAnonRecordDecls( const RecordDecl *RD, llvm::DIFile *Unit, unsigned LineNo, StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext) { @@ -3241,7 +3151,6 @@ llvm::DIGlobalVariable *CGDebugInfo::CollectAnonRecordDecls( return GV; } -/// EmitGlobalVariable - Emit information about a global variable. void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, const VarDecl *D) { assert(DebugKind >= CodeGenOptions::LimitedDebugInfo); @@ -3274,7 +3183,6 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, DeclCache[D->getCanonicalDecl()].reset(static_cast<llvm::Metadata *>(GV)); } -/// EmitGlobalVariable - Emit global variable's debug info. void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init) { assert(DebugKind >= CodeGenOptions::LimitedDebugInfo); @@ -3380,8 +3288,6 @@ CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) { return R; } -/// getOrCreateNamesSpace - Return namespace descriptor for the given -/// namespace decl. llvm::DINamespace * CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) { NSDecl = NSDecl->getCanonicalDecl(); diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 10d3b0d9ab02..4c77a8d28974 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -26,26 +26,26 @@ #include "llvm/Support/Allocator.h" namespace llvm { - class MDNode; +class MDNode; } namespace clang { - class CXXMethodDecl; - class VarDecl; - class ObjCInterfaceDecl; - class ObjCIvarDecl; - class ClassTemplateSpecializationDecl; - class GlobalDecl; - class UsingDecl; +class CXXMethodDecl; +class VarDecl; +class ObjCInterfaceDecl; +class ObjCIvarDecl; +class ClassTemplateSpecializationDecl; +class GlobalDecl; +class UsingDecl; namespace CodeGen { - class CodeGenModule; - class CodeGenFunction; - class CGBlockInfo; +class CodeGenModule; +class CodeGenFunction; +class CGBlockInfo; -/// \brief This class gathers all debug information during compilation -/// and is responsible for emitting to llvm globals or pass directly to -/// the backend. +/// This class gathers all debug information during compilation and is +/// responsible for emitting to llvm globals or pass directly to the +/// backend. class CGDebugInfo { friend class ApplyDebugLocation; friend class SaveAndRestoreLocation; @@ -65,9 +65,8 @@ class CGDebugInfo { llvm::DIType *OCLImage2dArrayDITy = nullptr; llvm::DIType *OCLImage3dDITy = nullptr; llvm::DIType *OCLEventDITy = nullptr; - llvm::DIType *BlockLiteralGeneric = nullptr; - /// \brief Cache of previously constructed Types. + /// Cache of previously constructed Types. llvm::DenseMap<const void *, llvm::TrackingMDRef> TypeCache; struct ObjCInterfaceCacheEntry { @@ -79,41 +78,40 @@ class CGDebugInfo { : Type(Type), Decl(Decl), Unit(Unit) {} }; - /// \brief Cache of previously constructed interfaces - /// which may change. + /// Cache of previously constructed interfaces which may change. llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache; - /// \brief Cache of references to AST files such as PCHs or modules. + /// Cache of references to AST files such as PCHs or modules. llvm::DenseMap<uint64_t, llvm::DIModule *> ModuleRefCache; - /// \brief list of interfaces we want to keep even if orphaned. + /// List of interfaces we want to keep even if orphaned. std::vector<void *> RetainedTypes; - /// \brief Cache of forward declared types to RAUW at the end of + /// Cache of forward declared types to RAUW at the end of /// compilation. std::vector<std::pair<const TagType *, llvm::TrackingMDRef>> ReplaceMap; - /// \brief Cache of replaceable forward declarartions (functions and + /// Cache of replaceable forward declarartions (functions and /// variables) to RAUW at the end of compilation. std::vector<std::pair<const DeclaratorDecl *, llvm::TrackingMDRef>> FwdDeclReplaceMap; - // LexicalBlockStack - Keep track of our current nested lexical block. + /// Keep track of our current nested lexical block. std::vector<llvm::TypedTrackingMDRef<llvm::DIScope>> LexicalBlockStack; llvm::DenseMap<const Decl *, llvm::TrackingMDRef> RegionMap; - // FnBeginRegionCount - Keep track of LexicalBlockStack counter at the - // beginning of a function. This is used to pop unbalanced regions at - // the end of a function. + /// Keep track of LexicalBlockStack counter at the beginning of a + /// function. This is used to pop unbalanced regions at the end of a + /// function. std::vector<unsigned> FnBeginRegionCount; - /// \brief This is a storage for names that are - /// constructed on demand. For example, C++ destructors, C++ operators etc.. + /// This is a storage for names that are constructed on demand. For + /// example, C++ destructors, C++ operators etc.. llvm::BumpPtrAllocator DebugInfoNames; StringRef CWDName; llvm::DenseMap<const char *, llvm::TrackingMDRef> DIFileCache; llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPCache; - /// \brief Cache declarations relevant to DW_TAG_imported_declarations (C++ + /// Cache declarations relevant to DW_TAG_imported_declarations (C++ /// using declarations) that aren't covered by other more specific caches. llvm::DenseMap<const Decl *, llvm::TrackingMDRef> DeclCache; llvm::DenseMap<const NamespaceDecl *, llvm::TrackingMDRef> NameSpaceCache; @@ -122,6 +120,9 @@ class CGDebugInfo { llvm::DenseMap<const Decl *, llvm::TrackingMDRef> StaticDataMemberCache; /// Helper functions for getOrCreateType. + /// @{ + /// Currently the checksum of an interface includes the number of + /// ivars and property accessors. unsigned Checksum(const ObjCInterfaceDecl *InterfaceDecl); llvm::DIType *CreateType(const BuiltinType *Ty); llvm::DIType *CreateType(const ComplexType *Ty); @@ -133,14 +134,17 @@ class CGDebugInfo { llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const BlockPointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F); + /// Get structure or union type. llvm::DIType *CreateType(const RecordType *Tyg); llvm::DIType *CreateTypeDefinition(const RecordType *Ty); llvm::DICompositeType *CreateLimitedType(const RecordType *Ty); void CollectContainingType(const CXXRecordDecl *RD, llvm::DICompositeType *CT); + /// Get Objective-C interface type. llvm::DIType *CreateType(const ObjCInterfaceType *Ty, llvm::DIFile *F); llvm::DIType *CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile *F); + /// Get Objective-C object type. llvm::DIType *CreateType(const ObjCObjectType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const VectorType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const ArrayType *Ty, llvm::DIFile *F); @@ -148,10 +152,25 @@ class CGDebugInfo { llvm::DIType *CreateType(const RValueReferenceType *Ty, llvm::DIFile *Unit); llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F); + /// Get enumeration type. llvm::DIType *CreateEnumType(const EnumType *Ty); llvm::DIType *CreateTypeDefinition(const EnumType *Ty); + /// Look up the completed type for a self pointer in the TypeCache and + /// create a copy of it with the ObjectPointer and Artificial flags + /// set. If the type is not cached, a new one is created. This should + /// never happen though, since creating a type for the implicit self + /// argument implies that we already parsed the interface definition + /// and the ivar declarations in the implementation. llvm::DIType *CreateSelfType(const QualType &QualTy, llvm::DIType *Ty); + /// @} + + /// Get the type from the cache or return null type if it doesn't + /// exist. llvm::DIType *getTypeOrNull(const QualType); + /// Return the debug type for a C++ method. + /// \arg CXXMethodDecl is of FunctionType. This function type is + /// not updated to include implicit \c this pointer. Use this routine + /// to get a method type which includes \c this pointer. llvm::DISubroutineType *getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile *F); llvm::DISubroutineType * @@ -159,7 +178,9 @@ class CGDebugInfo { llvm::DIFile *Unit); llvm::DISubroutineType * getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F); + /// \return debug info descriptor for vtable. llvm::DIType *getOrCreateVTablePtrType(llvm::DIFile *F); + /// \return namespace descriptor for the given namespace decl. llvm::DINamespace *getOrCreateNameSpace(const NamespaceDecl *N); llvm::DIType *getOrCreateTypeDeclaration(QualType PointeeTy, llvm::DIFile *F); llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, @@ -168,23 +189,37 @@ class CGDebugInfo { llvm::Value *getCachedInterfaceTypeOrNull(const QualType Ty); llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache); + /// A helper function to create a subprogram for a single member + /// function GlobalDecl. llvm::DISubprogram *CreateCXXMemberFunction(const CXXMethodDecl *Method, llvm::DIFile *F, llvm::DIType *RecordTy); + /// A helper function to collect debug info for C++ member + /// functions. This is used while creating debug info entry for a + /// Record. void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, llvm::DIFile *F, SmallVectorImpl<llvm::Metadata *> &E, llvm::DIType *T); + /// A helper function to collect debug info for C++ base + /// classes. This is used while creating debug info entry for a + /// Record. void CollectCXXBases(const CXXRecordDecl *Decl, llvm::DIFile *F, SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy); + /// A helper function to collect template parameters. llvm::DINodeArray CollectTemplateParams(const TemplateParameterList *TPList, ArrayRef<TemplateArgument> TAList, llvm::DIFile *Unit); + /// A helper function to collect debug info for function template + /// parameters. llvm::DINodeArray CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile *Unit); + + /// A helper function to collect debug info for template + /// parameters. llvm::DINodeArray CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS, llvm::DIFile *F); @@ -195,7 +230,8 @@ class CGDebugInfo { llvm::DIFile *tunit, llvm::DIScope *scope, const RecordDecl *RD = nullptr); - // Helpers for collecting fields of a record. + /// Helpers for collecting fields of a record. + /// @{ void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &E, llvm::DIType *RecordTy); @@ -210,11 +246,13 @@ class CGDebugInfo { SmallVectorImpl<llvm::Metadata *> &E, llvm::DICompositeType *RecordTy); + /// If the C++ class has vtable info then insert appropriate debug + /// info entry in EltTys vector. void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile *F, SmallVectorImpl<llvm::Metadata *> &EltTys); + /// @} - // CreateLexicalBlock - Create a new lexical block node and push it on - // the stack. + /// Create a new lexical block node and push it on the stack. void CreateLexicalBlock(SourceLocation Loc); public: @@ -223,86 +261,84 @@ public: void finalize(); - /// \brief Update the current source location. If \arg loc is - /// invalid it is ignored. + /// Update the current source location. If \arg loc is invalid it is + /// ignored. void setLocation(SourceLocation Loc); - /// \brief Emit metadata to indicate a change in line/column - /// information in the source file. + /// Emit metadata to indicate a change in line/column information in + /// the source file. If the location is invalid, the previous + /// location will be reused. void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); - /// \brief Emit a call to llvm.dbg.function.start to indicate + /// Emit a call to llvm.dbg.function.start to indicate /// start of a new function. /// \param Loc The location of the function header. /// \param ScopeLoc The location of the function body. - void EmitFunctionStart(GlobalDecl GD, - SourceLocation Loc, SourceLocation ScopeLoc, - QualType FnType, llvm::Function *Fn, - CGBuilderTy &Builder); + void EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, + SourceLocation ScopeLoc, QualType FnType, + llvm::Function *Fn, CGBuilderTy &Builder); - /// \brief Constructs the debug code for exiting a function. + /// Constructs the debug code for exiting a function. void EmitFunctionEnd(CGBuilderTy &Builder); - /// \brief Emit metadata to indicate the beginning of a - /// new lexical block and push the block onto the stack. + /// Emit metadata to indicate the beginning of a new lexical block + /// and push the block onto the stack. void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc); - /// \brief Emit metadata to indicate the end of a new lexical - /// block and pop the current block. + /// Emit metadata to indicate the end of a new lexical block and pop + /// the current block. void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc); - /// \brief Emit call to llvm.dbg.declare for an automatic - /// variable declaration. + /// Emit call to \c llvm.dbg.declare for an automatic variable + /// declaration. void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI, CGBuilderTy &Builder); - /// \brief Emit call to llvm.dbg.declare for an - /// imported variable declaration in a block. + /// Emit call to \c llvm.dbg.declare for an imported variable + /// declaration in a block. void EmitDeclareOfBlockDeclRefVariable(const VarDecl *variable, llvm::Value *storage, CGBuilderTy &Builder, const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint = 0); - /// \brief Emit call to llvm.dbg.declare for an argument - /// variable declaration. + /// Emit call to \c llvm.dbg.declare for an argument variable + /// declaration. void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder); - /// \brief Emit call to - /// llvm.dbg.declare for the block-literal argument to a block - /// invocation function. + /// Emit call to \c llvm.dbg.declare for the block-literal argument + /// to a block invocation function. void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, llvm::Value *Arg, unsigned ArgNo, llvm::Value *LocalAddr, CGBuilderTy &Builder); - /// \brief Emit information about a global variable. + /// Emit information about a global variable. void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); - /// \brief Emit global variable's debug info. + /// Emit global variable's debug info. void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init); - /// \brief Emit C++ using directive. + /// Emit C++ using directive. void EmitUsingDirective(const UsingDirectiveDecl &UD); - /// \brief Emit the type explicitly casted to. + /// Emit the type explicitly casted to. void EmitExplicitCastType(QualType Ty); - /// \brief Emit C++ using declaration. + /// Emit C++ using declaration. void EmitUsingDecl(const UsingDecl &UD); - /// \brief Emit an @import declaration. + /// Emit an @import declaration. void EmitImportDecl(const ImportDecl &ID); - /// \brief Emit C++ namespace alias. + /// Emit C++ namespace alias. llvm::DIImportedEntity *EmitNamespaceAlias(const NamespaceAliasDecl &NA); - /// \brief Emit record type's standalone debug info. + /// Emit record type's standalone debug info. llvm::DIType *getOrCreateRecordType(QualType Ty, SourceLocation L); - /// \brief Emit an objective c interface type standalone - /// debug info. + /// Emit an Objective-C interface type standalone debug info. llvm::DIType *getOrCreateInterfaceType(QualType Ty, SourceLocation Loc); void completeType(const EnumDecl *ED); @@ -313,120 +349,124 @@ public: void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD); private: - /// \brief Emit call to llvm.dbg.declare for a variable declaration. + /// Emit call to llvm.dbg.declare for a variable declaration. /// Tag accepts custom types DW_TAG_arg_variable and DW_TAG_auto_variable, /// otherwise would be of type llvm::dwarf::Tag. void EmitDeclare(const VarDecl *decl, llvm::dwarf::Tag Tag, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder); - // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. - // See BuildByRefType. + /// Build up structure info for the byref. See \a BuildByRefType. llvm::DIType *EmitTypeForVarWithBlocksAttr(const VarDecl *VD, uint64_t *OffSet); - /// \brief Get context info for the decl. + /// Get context info for the decl. llvm::DIScope *getContextDescriptor(const Decl *Decl); llvm::DIScope *getCurrentContextDescriptor(const Decl *Decl); - /// \brief Create a forward decl for a RecordType in a given context. + /// Create a forward decl for a RecordType in a given context. llvm::DICompositeType *getOrCreateRecordFwdDecl(const RecordType *, llvm::DIScope *); - /// \brief Return current directory name. + /// Return current directory name. StringRef getCurrentDirname(); - /// \brief Create new compile unit. + /// Create new compile unit. void CreateCompileUnit(); - /// \brief Get the file debug info descriptor for the input - /// location. + /// Get the file debug info descriptor for the input location. llvm::DIFile *getOrCreateFile(SourceLocation Loc); - /// \brief Get the file info for main compile unit. + /// Get the file info for main compile unit. llvm::DIFile *getOrCreateMainFile(); - /// \brief Get the type from the cache or create a new type if - /// necessary. + /// Get the type from the cache or create a new type if necessary. llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg); - /// \brief Get a reference to a clang module. + /// Get a reference to a clang module. llvm::DIModule * getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod); - /// \brief Get the type from the cache or create a new - /// partial type if necessary. + /// Get the type from the cache or create a new partial type if + /// necessary. llvm::DIType *getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile *F); - /// \brief Create type metadata for a source language type. + /// Create type metadata for a source language type. llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg); - /// \brief return the underlying ObjCInterfaceDecl - /// if Ty is an ObjCInterface or a pointer to one. - ObjCInterfaceDecl* getObjCInterfaceDecl(QualType Ty); + /// Return the underlying ObjCInterfaceDecl if \arg Ty is an + /// ObjCInterface or a pointer to one. + ObjCInterfaceDecl *getObjCInterfaceDecl(QualType Ty); - /// \brief Create new member and increase Offset by FType's size. + /// Create new member and increase Offset by FType's size. llvm::DIType *CreateMemberType(llvm::DIFile *Unit, QualType FType, StringRef Name, uint64_t *Offset); - /// \brief Retrieve the DIDescriptor, if any, for the canonical form of this + /// Retrieve the DIDescriptor, if any, for the canonical form of this /// declaration. llvm::DINode *getDeclarationOrDefinition(const Decl *D); - /// \brief Return debug info descriptor to describe method + /// \return debug info descriptor to describe method /// declaration for the given method definition. llvm::DISubprogram *getFunctionDeclaration(const Decl *D); - /// Return debug info descriptor to describe in-class static data member - /// declaration for the given out-of-class definition. + /// \return debug info descriptor to describe in-class static data + /// member declaration for the given out-of-class definition. If D + /// is an out-of-class definition of a static data member of a + /// class, find its corresponding in-class declaration. llvm::DIDerivedType * getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D); - /// \brief Create a subprogram describing the forward - /// decalration represented in the given FunctionDecl. + /// Create a subprogram describing the forward declaration + /// represented in the given FunctionDecl. llvm::DISubprogram *getFunctionForwardDeclaration(const FunctionDecl *FD); - /// \brief Create a global variable describing the forward decalration + /// Create a global variable describing the forward decalration /// represented in the given VarDecl. llvm::DIGlobalVariable * getGlobalVariableForwardDeclaration(const VarDecl *VD); - /// Return a global variable that represents one of the collection of - /// global variables created for an anonmyous union. + /// \brief Return a global variable that represents one of the + /// collection of global variables created for an anonmyous union. + /// + /// Recursively collect all of the member fields of a global + /// anonymous decl and create static variables for them. The first + /// time this is called it needs to be on a union and then from + /// there we can have additional unnamed fields. llvm::DIGlobalVariable * CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile *Unit, unsigned LineNo, StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext); - /// \brief Get function name for the given FunctionDecl. If the - /// name is constructed on demand (e.g. C++ destructor) then the name - /// is stored on the side. + /// Get function name for the given FunctionDecl. If the name is + /// constructed on demand (e.g., C++ destructor) then the name is + /// stored on the side. StringRef getFunctionName(const FunctionDecl *FD); - /// \brief Returns the unmangled name of an Objective-C method. + /// Returns the unmangled name of an Objective-C method. /// This is the display name for the debugging info. StringRef getObjCMethodName(const ObjCMethodDecl *FD); - /// \brief Return selector name. This is used for debugging + /// Return selector name. This is used for debugging /// info. StringRef getSelectorName(Selector S); - /// \brief Get class name including template argument list. + /// Get class name including template argument list. StringRef getClassName(const RecordDecl *RD); - /// \brief Get vtable name for the given Class. + /// Get the vtable name for the given class. StringRef getVTableName(const CXXRecordDecl *Decl); - /// \brief Get line number for the location. If location is invalid + /// Get line number for the location. If location is invalid /// then use current location. unsigned getLineNumber(SourceLocation Loc); - /// \brief Get column number for the location. If location is + /// Get column number for the location. If location is /// invalid then use current location. /// \param Force Assume DebugColumnInfo option is true. - unsigned getColumnNumber(SourceLocation Loc, bool Force=false); + unsigned getColumnNumber(SourceLocation Loc, bool Force = false); - /// \brief Collect various properties of a FunctionDecl. + /// Collect various properties of a FunctionDecl. /// \param GD A GlobalDecl whose getDecl() must return a FunctionDecl. void collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit, StringRef &Name, StringRef &LinkageName, @@ -434,12 +474,12 @@ private: llvm::DINodeArray &TParamsArray, unsigned &Flags); - /// \brief Collect various properties of a VarDecl. + /// Collect various properties of a VarDecl. void collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit, unsigned &LineNo, QualType &T, StringRef &Name, StringRef &LinkageName, llvm::DIScope *&VDContext); - /// \brief Allocate a copy of \p A using the DebugInfoNames allocator + /// Allocate a copy of \p A using the DebugInfoNames allocator /// and return a reference to it. If multiple arguments are given the strings /// are concatenated. StringRef internString(StringRef A, StringRef B = StringRef()) { @@ -450,7 +490,7 @@ private: } }; -/// \brief A scoped helper to set the current debug location to the specified +/// A scoped helper to set the current debug location to the specified /// location or preferred location of the specified Expr. class ApplyDebugLocation { private: @@ -460,55 +500,56 @@ private: llvm::DebugLoc OriginalLocation; CodeGenFunction &CGF; -public: - /// \brief Set the location to the (valid) TemporaryLocation. +public: + /// Set the location to the (valid) TemporaryLocation. ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation); ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E); ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc); ~ApplyDebugLocation(); - /// \brief Apply TemporaryLocation if it is valid. Otherwise switch to an - /// artificial debug location that has a valid scope, but no line information. + /// \brief Apply TemporaryLocation if it is valid. Otherwise switch + /// to an artificial debug location that has a valid scope, but no + /// line information. /// - /// Artificial locations are useful when emitting compiler-generated helper - /// functions that have no source location associated with them. The DWARF - /// specification allows the compiler to use the special line number 0 to - /// indicate code that can not be attributed to any source location. Note that - /// passing an empty SourceLocation to CGDebugInfo::setLocation() will result - /// in the last valid location being reused. + /// Artificial locations are useful when emitting compiler-generated + /// helper functions that have no source location associated with + /// them. The DWARF specification allows the compiler to use the + /// special line number 0 to indicate code that can not be + /// attributed to any source location. Note that passing an empty + /// SourceLocation to CGDebugInfo::setLocation() will result in the + /// last valid location being reused. static ApplyDebugLocation CreateArtificial(CodeGenFunction &CGF) { return ApplyDebugLocation(CGF, false, SourceLocation()); } - /// \brief Apply TemporaryLocation if it is valid. Otherwise switch to an - /// artificial debug location that has a valid scope, but no line information. - static ApplyDebugLocation CreateDefaultArtificial(CodeGenFunction &CGF, - SourceLocation TemporaryLocation) { + /// \brief Apply TemporaryLocation if it is valid. Otherwise switch + /// to an artificial debug location that has a valid scope, but no + /// line information. + static ApplyDebugLocation + CreateDefaultArtificial(CodeGenFunction &CGF, + SourceLocation TemporaryLocation) { return ApplyDebugLocation(CGF, false, TemporaryLocation); } - /// \brief Set the IRBuilder to not attach debug locations. Note that passing - /// an empty SourceLocation to CGDebugInfo::setLocation() will result in the - /// last valid location being reused. Note that all instructions that do not - /// have a location at the beginning of a function are counted towards to - /// funciton prologue. + /// Set the IRBuilder to not attach debug locations. Note that + /// passing an empty SourceLocation to \a CGDebugInfo::setLocation() + /// will result in the last valid location being reused. Note that + /// all instructions that do not have a location at the beginning of + /// a function are counted towards to funciton prologue. static ApplyDebugLocation CreateEmpty(CodeGenFunction &CGF) { return ApplyDebugLocation(CGF, true, SourceLocation()); } /// \brief Apply TemporaryLocation if it is valid. Otherwise set the IRBuilder /// to not attach debug locations. - static ApplyDebugLocation CreateDefaultEmpty(CodeGenFunction &CGF, - SourceLocation TemporaryLocation) { + static ApplyDebugLocation + CreateDefaultEmpty(CodeGenFunction &CGF, SourceLocation TemporaryLocation) { return ApplyDebugLocation(CGF, true, TemporaryLocation); } - }; - } // namespace CodeGen } // namespace clang - #endif diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 839c2e474ca3..96aa8c68e004 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -79,6 +79,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Captured: case Decl::ClassScopeFunctionSpecialization: case Decl::UsingShadow: + case Decl::ObjCTypeParam: llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; @@ -987,7 +988,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { llvm::Value *Stack = CreateTempAlloca(Int8PtrTy, "saved_stack"); llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stacksave); - llvm::Value *V = Builder.CreateCall(F, {}); + llvm::Value *V = Builder.CreateCall(F); Builder.CreateStore(V, Stack); diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 4c8501724bd8..7b8368ee2b32 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -20,6 +20,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/TargetBuiltins.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicInst.h" @@ -1279,14 +1280,6 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { } void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { - // FIXME: Implement SEH on other architectures. - const llvm::Triple &T = CGM.getTarget().getTriple(); - if (T.getArch() != llvm::Triple::x86_64 || - !T.isKnownWindowsMSVCEnvironment()) { - ErrorUnsupported(&S, "__try statement"); - return; - } - EnterSEHTryStmt(S); { JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); @@ -1311,24 +1304,27 @@ struct PerformSEHFinally : EHScopeStack::Cleanup { void Emit(CodeGenFunction &CGF, Flags F) override { ASTContext &Context = CGF.getContext(); - QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy}; - FunctionProtoType::ExtProtoInfo EPI; - const auto *FTP = cast<FunctionType>( - Context.getFunctionType(Context.VoidTy, ArgTys, EPI)); + CodeGenModule &CGM = CGF.CGM; CallArgList Args; + + // Compute the two argument values. + QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy}; + llvm::Value *LocalAddrFn = CGM.getIntrinsic(llvm::Intrinsic::localaddress); + llvm::Value *FP = CGF.Builder.CreateCall(LocalAddrFn); llvm::Value *IsForEH = llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup()); Args.add(RValue::get(IsForEH), ArgTys[0]); - - CodeGenModule &CGM = CGF.CGM; - llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0); - llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress); - llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero); Args.add(RValue::get(FP), ArgTys[1]); + // Arrange a two-arg function info and type. + FunctionProtoType::ExtProtoInfo EPI; + const auto *FPT = cast<FunctionProtoType>( + Context.getFunctionType(Context.VoidTy, ArgTys, EPI)); const CGFunctionInfo &FnInfo = - CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false); + CGM.getTypes().arrangeFreeFunctionCall(Args, FPT, + /*chainCall=*/false); + CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args); } }; @@ -1340,9 +1336,15 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> { CodeGenFunction &ParentCGF; const VarDecl *ParentThis; SmallVector<const VarDecl *, 4> Captures; + llvm::Value *SEHCodeSlot = nullptr; CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis) : ParentCGF(ParentCGF), ParentThis(ParentThis) {} + // Return true if we need to do any capturing work. + bool foundCaptures() { + return !Captures.empty() || SEHCodeSlot; + } + void Visit(const Stmt *S) { // See if this is a capture, then recurse. ConstStmtVisitor<CaptureFinder>::Visit(S); @@ -1366,27 +1368,106 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> { void VisitCXXThisExpr(const CXXThisExpr *E) { Captures.push_back(ParentThis); } + + void VisitCallExpr(const CallExpr *E) { + // We only need to add parent frame allocations for these builtins in x86. + if (ParentCGF.getTarget().getTriple().getArch() != llvm::Triple::x86) + return; + + unsigned ID = E->getBuiltinCallee(); + switch (ID) { + case Builtin::BI__exception_code: + case Builtin::BI_exception_code: + // This is the simple case where we are the outermost finally. All we + // have to do here is make sure we escape this and recover it in the + // outlined handler. + if (!SEHCodeSlot) + SEHCodeSlot = ParentCGF.SEHCodeSlotStack.back(); + break; + } + } }; } +llvm::Value *CodeGenFunction::recoverAddrOfEscapedLocal( + CodeGenFunction &ParentCGF, llvm::Value *ParentVar, llvm::Value *ParentFP) { + llvm::CallInst *RecoverCall = nullptr; + CGBuilderTy Builder(AllocaInsertPt); + if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) { + // Mark the variable escaped if nobody else referenced it and compute the + // localescape index. + auto InsertPair = ParentCGF.EscapedLocals.insert( + std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size())); + int FrameEscapeIdx = InsertPair.first->second; + // call i8* @llvm.localrecover(i8* bitcast(@parentFn), i8* %fp, i32 N) + llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::localrecover); + llvm::Constant *ParentI8Fn = + llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); + RecoverCall = Builder.CreateCall( + FrameRecoverFn, {ParentI8Fn, ParentFP, + llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); + + } else { + // If the parent didn't have an alloca, we're doing some nested outlining. + // Just clone the existing localrecover call, but tweak the FP argument to + // use our FP value. All other arguments are constants. + auto *ParentRecover = + cast<llvm::IntrinsicInst>(ParentVar->stripPointerCasts()); + assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::localrecover && + "expected alloca or localrecover in parent LocalDeclMap"); + RecoverCall = cast<llvm::CallInst>(ParentRecover->clone()); + RecoverCall->setArgOperand(1, ParentFP); + RecoverCall->insertBefore(AllocaInsertPt); + } + + // Bitcast the variable, rename it, and insert it in the local decl map. + llvm::Value *ChildVar = + Builder.CreateBitCast(RecoverCall, ParentVar->getType()); + ChildVar->setName(ParentVar->getName()); + return ChildVar; +} + void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt, - llvm::Value *ParentFP) { + bool IsFilter) { // Find all captures in the Stmt. CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl); Finder.Visit(OutlinedStmt); - // Typically there are no captures and we can exit early. - if (Finder.Captures.empty()) + // We can exit early on x86_64 when there are no captures. We just have to + // save the exception code in filters so that __exception_code() works. + if (!Finder.foundCaptures() && + CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { + if (IsFilter) + EmitSEHExceptionCodeSave(ParentCGF, nullptr, nullptr); return; + } - // Prepare the first two arguments to llvm.framerecover. - llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( - &CGM.getModule(), llvm::Intrinsic::framerecover); - llvm::Constant *ParentI8Fn = - llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); + llvm::Value *EntryEBP = nullptr; + llvm::Value *ParentFP; + if (IsFilter && CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) { + // 32-bit SEH filters need to be careful about FP recovery. The end of the + // EH registration is passed in as the EBP physical register. We can + // recover that with llvm.frameaddress(1), and adjust that to recover the + // parent's true frame pointer. + CGBuilderTy Builder(AllocaInsertPt); + EntryEBP = Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::frameaddress), {Builder.getInt32(1)}); + llvm::Function *RecoverFPIntrin = + CGM.getIntrinsic(llvm::Intrinsic::x86_seh_recoverfp); + llvm::Constant *ParentI8Fn = + llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); + ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryEBP}); + } else { + // Otherwise, for x64 and 32-bit finally functions, the parent FP is the + // second parameter. + auto AI = CurFn->arg_begin(); + ++AI; + ParentFP = AI; + } - // Create llvm.framerecover calls for all captures. + // Create llvm.localrecover calls for all captures. for (const VarDecl *VD : Finder.Captures) { if (isa<ImplicitParamDecl>(VD)) { CGM.ErrorUnsupported(VD, "'this' captured by SEH"); @@ -1407,49 +1488,63 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, continue; llvm::Value *ParentVar = I->second; - llvm::CallInst *RecoverCall = nullptr; - CGBuilderTy Builder(AllocaInsertPt); - if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) { - // Mark the variable escaped if nobody else referenced it and compute the - // frameescape index. - auto InsertPair = - ParentCGF.EscapedLocals.insert(std::make_pair(ParentAlloca, -1)); - if (InsertPair.second) - InsertPair.first->second = ParentCGF.EscapedLocals.size() - 1; - int FrameEscapeIdx = InsertPair.first->second; - // call i8* @llvm.framerecover(i8* bitcast(@parentFn), i8* %fp, i32 N) - RecoverCall = Builder.CreateCall( - FrameRecoverFn, {ParentI8Fn, ParentFP, - llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); - - } else { - // If the parent didn't have an alloca, we're doing some nested outlining. - // Just clone the existing framerecover call, but tweak the FP argument to - // use our FP value. All other arguments are constants. - auto *ParentRecover = - cast<llvm::IntrinsicInst>(ParentVar->stripPointerCasts()); - assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::framerecover && - "expected alloca or framerecover in parent LocalDeclMap"); - RecoverCall = cast<llvm::CallInst>(ParentRecover->clone()); - RecoverCall->setArgOperand(1, ParentFP); - RecoverCall->insertBefore(AllocaInsertPt); - } + LocalDeclMap[VD] = + recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP); + } - // Bitcast the variable, rename it, and insert it in the local decl map. - llvm::Value *ChildVar = - Builder.CreateBitCast(RecoverCall, ParentVar->getType()); - ChildVar->setName(ParentVar->getName()); - LocalDeclMap[VD] = ChildVar; + if (Finder.SEHCodeSlot) { + SEHCodeSlotStack.push_back( + recoverAddrOfEscapedLocal(ParentCGF, Finder.SEHCodeSlot, ParentFP)); } + + if (IsFilter) + EmitSEHExceptionCodeSave(ParentCGF, ParentFP, EntryEBP); } /// Arrange a function prototype that can be called by Windows exception /// handling personalities. On Win64, the prototype looks like: /// RetTy func(void *EHPtrs, void *ParentFP); void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, - StringRef Name, QualType RetTy, - FunctionArgList &Args, + bool IsFilter, const Stmt *OutlinedStmt) { + SourceLocation StartLoc = OutlinedStmt->getLocStart(); + + // Get the mangled function name. + SmallString<128> Name; + { + llvm::raw_svector_ostream OS(Name); + const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; + const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl); + assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); + MangleContext &Mangler = CGM.getCXXABI().getMangleContext(); + if (IsFilter) + Mangler.mangleSEHFilterExpression(Parent, OS); + else + Mangler.mangleSEHFinallyBlock(Parent, OS); + } + + FunctionArgList Args; + if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 || !IsFilter) { + // All SEH finally functions take two parameters. Win64 filters take two + // parameters. Win32 filters take no parameters. + if (IsFilter) { + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("exception_pointers"), + getContext().VoidPtrTy)); + } else { + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("abnormal_termination"), + getContext().UnsignedCharTy)); + } + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); + } + + QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy; + llvm::Function *ParentFn = ParentCGF.CurFn; const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration( RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false); @@ -1474,10 +1569,7 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart()); CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn); - - auto AI = Fn->arg_begin(); - ++AI; - EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI); + EmitCapturedLocals(ParentCGF, OutlinedStmt, IsFilter); } /// Create a stub filter function that will ultimately hold the code of the @@ -1487,37 +1579,7 @@ llvm::Function * CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, const SEHExceptStmt &Except) { const Expr *FilterExpr = Except.getFilterExpr(); - SourceLocation StartLoc = FilterExpr->getLocStart(); - - SEHPointersDecl = ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy); - FunctionArgList Args; - Args.push_back(SEHPointersDecl); - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); - - // Get the mangled function name. - SmallString<128> Name; - { - llvm::raw_svector_ostream OS(Name); - const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; - const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl); - assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); - CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS); - } - - startOutlinedSEHHelper(ParentCGF, Name, getContext().LongTy, Args, - FilterExpr); - - // Mark finally block calls as nounwind and noinline to make LLVM's job a - // little easier. - // FIXME: Remove these restrictions in the future. - CurFn->addFnAttr(llvm::Attribute::NoUnwind); - CurFn->addFnAttr(llvm::Attribute::NoInline); - - EmitSEHExceptionCodeSave(); + startOutlinedSEHHelper(ParentCGF, true, FilterExpr); // Emit the original filter expression, convert to i32, and return. llvm::Value *R = EmitScalarExpr(FilterExpr); @@ -1534,29 +1596,13 @@ llvm::Function * CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, const SEHFinallyStmt &Finally) { const Stmt *FinallyBlock = Finally.getBlock(); - SourceLocation StartLoc = FinallyBlock->getLocStart(); + startOutlinedSEHHelper(ParentCGF, false, FinallyBlock); - FunctionArgList Args; - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("abnormal_termination"), - getContext().UnsignedCharTy)); - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, StartLoc, - &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); - - // Get the mangled function name. - SmallString<128> Name; - { - llvm::raw_svector_ostream OS(Name); - const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; - const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl); - assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); - CGM.getCXXABI().getMangleContext().mangleSEHFinallyBlock(Parent, OS); - } - - startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args, - FinallyBlock); + // Mark finally block calls as nounwind and noinline to make LLVM's job a + // little easier. + // FIXME: Remove these restrictions in the future. + CurFn->addFnAttr(llvm::Attribute::NoUnwind); + CurFn->addFnAttr(llvm::Attribute::NoInline); // Emit the original filter expression, convert to i32, and return. EmitStmt(FinallyBlock); @@ -1566,44 +1612,58 @@ CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, return CurFn; } -void CodeGenFunction::EmitSEHExceptionCodeSave() { +void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF, + llvm::Value *ParentFP, + llvm::Value *EntryEBP) { + // Get the pointer to the EXCEPTION_POINTERS struct. This is returned by the + // __exception_info intrinsic. + if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { + // On Win64, the info is passed as the first parameter to the filter. + auto AI = CurFn->arg_begin(); + SEHInfo = AI; + SEHCodeSlotStack.push_back( + CreateMemTemp(getContext().IntTy, "__exception_code")); + } else { + // On Win32, the EBP on entry to the filter points to the end of an + // exception registration object. It contains 6 32-bit fields, and the info + // pointer is stored in the second field. So, GEP 20 bytes backwards and + // load the pointer. + SEHInfo = Builder.CreateConstInBoundsGEP1_32(Int8Ty, EntryEBP, -20); + SEHInfo = Builder.CreateBitCast(SEHInfo, Int8PtrTy->getPointerTo()); + SEHInfo = Builder.CreateLoad(Int8PtrTy, SEHInfo); + SEHCodeSlotStack.push_back(recoverAddrOfEscapedLocal( + ParentCGF, ParentCGF.SEHCodeSlotStack.back(), ParentFP)); + } + // Save the exception code in the exception slot to unify exception access in // the filter function and the landing pad. // struct EXCEPTION_POINTERS { // EXCEPTION_RECORD *ExceptionRecord; // CONTEXT *ContextRecord; // }; - // void *exn.slot = - // (void *)(uintptr_t)exception_pointers->ExceptionRecord->ExceptionCode; - llvm::Value *Ptrs = Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl)); + // int exceptioncode = exception_pointers->ExceptionRecord->ExceptionCode; llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo(); llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr); - Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo()); + llvm::Value *Ptrs = Builder.CreateBitCast(SEHInfo, PtrsTy->getPointerTo()); llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, Ptrs, 0); Rec = Builder.CreateLoad(Rec); llvm::Value *Code = Builder.CreateLoad(Rec); - Code = Builder.CreateZExt(Code, CGM.IntPtrTy); - // FIXME: Change landing pads to produce {i32, i32} and make the exception - // slot an i32. - Code = Builder.CreateIntToPtr(Code, CGM.VoidPtrTy); - Builder.CreateStore(Code, getExceptionSlot()); + assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except"); + Builder.CreateStore(Code, SEHCodeSlotStack.back()); } llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() { // Sema should diagnose calling this builtin outside of a filter context, but // don't crash if we screw up. - if (!SEHPointersDecl) + if (!SEHInfo) return llvm::UndefValue::get(Int8PtrTy); - return Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl)); + assert(SEHInfo->getType() == Int8PtrTy); + return SEHInfo; } llvm::Value *CodeGenFunction::EmitSEHExceptionCode() { - // If we're in a landing pad or filter function, the exception slot contains - // the code. - assert(ExceptionSlot); - llvm::Value *Code = - Builder.CreatePtrToInt(getExceptionFromSlot(), CGM.IntPtrTy); - return Builder.CreateTrunc(Code, CGM.Int32Ty); + assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except"); + return Builder.CreateLoad(Int32Ty, SEHCodeSlotStack.back()); } llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { @@ -1616,9 +1676,11 @@ llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true); if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) { - // Push a cleanup for __finally blocks. + // Outline the finally block. llvm::Function *FinallyFunc = HelperCGF.GenerateSEHFinallyFunction(*this, *Finally); + + // Push a cleanup for __finally blocks. EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc); return; } @@ -1627,12 +1689,16 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { const SEHExceptStmt *Except = S.getExceptHandler(); assert(Except); EHCatchScope *CatchScope = EHStack.pushCatch(1); + SEHCodeSlotStack.push_back( + CreateMemTemp(getContext().IntTy, "__exception_code")); - // If the filter is known to evaluate to 1, then we can use the clause "catch - // i8* null". + // If the filter is known to evaluate to 1, then we can use the clause + // "catch i8* null". We can't do this on x86 because the filter has to save + // the exception code. llvm::Constant *C = CGM.EmitConstantExpr(Except->getFilterExpr(), getContext().IntTy, this); - if (C && C->isOneValue()) { + if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C && + C->isOneValue()) { CatchScope->setCatchAllHandler(0, createBasicBlock("__except")); return; } @@ -1664,6 +1730,7 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { if (!CatchScope.hasEHBranches()) { CatchScope.clearHandlerBlocks(); EHStack.popCatch(); + SEHCodeSlotStack.pop_back(); return; } @@ -1683,9 +1750,20 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { EmitBlockAfterUses(ExceptBB); + // On Win64, the exception pointer is the exception code. Copy it to the slot. + if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { + llvm::Value *Code = + Builder.CreatePtrToInt(getExceptionFromSlot(), IntPtrTy); + Code = Builder.CreateTrunc(Code, Int32Ty); + Builder.CreateStore(Code, SEHCodeSlotStack.back()); + } + // Emit the __except body. EmitStmt(Except->getBlock()); + // End the lifetime of the exception code. + SEHCodeSlotStack.pop_back(); + if (HaveInsertPoint()) Builder.CreateBr(ContBB); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 175763c4e815..9c3dfe52716b 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1356,14 +1356,15 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) { const CGBitFieldInfo &Info = LV.getBitFieldInfo(); + CharUnits Align = LV.getAlignment().alignmentAtOffset(Info.StorageOffset); // Get the output type. llvm::Type *ResLTy = ConvertType(LV.getType()); llvm::Value *Ptr = LV.getBitFieldAddr(); - llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), - "bf.load"); - cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment); + llvm::Value *Val = Builder.CreateAlignedLoad(Ptr, Align.getQuantity(), + LV.isVolatileQualified(), + "bf.load"); if (Info.IsSigned) { assert(static_cast<unsigned>(Info.Offset + Info.Size) <= Info.StorageSize); @@ -1559,6 +1560,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, llvm::Value **Result) { const CGBitFieldInfo &Info = Dst.getBitFieldInfo(); + CharUnits Align = Dst.getAlignment().alignmentAtOffset(Info.StorageOffset); llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType()); llvm::Value *Ptr = Dst.getBitFieldAddr(); @@ -1575,9 +1577,9 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // and mask together with source before storing. if (Info.StorageSize != Info.Size) { assert(Info.StorageSize > Info.Size && "Invalid bitfield size."); - llvm::Value *Val = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(), - "bf.load"); - cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment); + llvm::Value *Val = Builder.CreateAlignedLoad(Ptr, Align.getQuantity(), + Dst.isVolatileQualified(), + "bf.load"); // Mask the source value as needed. if (!hasBooleanRepresentation(Dst.getType())) @@ -1603,9 +1605,8 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, } // Write the new value back out. - llvm::StoreInst *Store = Builder.CreateStore(SrcVal, Ptr, - Dst.isVolatileQualified()); - Store->setAlignment(Info.StorageAlignment); + Builder.CreateAlignedStore(SrcVal, Ptr, Align.getQuantity(), + Dst.isVolatileQualified()); // Return the new value of the bit-field, if requested. if (Result) { @@ -2415,8 +2416,7 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) { } llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) { - llvm::CallInst *TrapCall = - Builder.CreateCall(CGM.getIntrinsic(IntrID), {}); + llvm::CallInst *TrapCall = Builder.CreateCall(CGM.getIntrinsic(IntrID)); if (!CGM.getCodeGenOpts().TrapFuncName.empty()) TrapCall->addAttribute(llvm::AttributeSet::FunctionIndex, diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 747326e4c5bc..eb76ad1ce1f7 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -31,10 +31,9 @@ using namespace CodeGen; typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult; static TryEmitResult tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e); -static RValue AdjustRelatedResultType(CodeGenFunction &CGF, - QualType ET, - const ObjCMethodDecl *Method, - RValue Result); +static RValue AdjustObjCObjectType(CodeGenFunction &CGF, + QualType ET, + RValue Result); /// Given the address of a variable of pointer type, find the correct /// null to store into it. @@ -248,23 +247,22 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) { return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol()); } -/// \brief Adjust the type of the result of an Objective-C message send -/// expression when the method has a related result type. -static RValue AdjustRelatedResultType(CodeGenFunction &CGF, - QualType ExpT, - const ObjCMethodDecl *Method, - RValue Result) { - if (!Method) +/// \brief Adjust the type of an Objective-C object that doesn't match up due +/// to type erasure at various points, e.g., related result types or the use +/// of parameterized classes. +static RValue AdjustObjCObjectType(CodeGenFunction &CGF, QualType ExpT, + RValue Result) { + if (!ExpT->isObjCRetainableType()) return Result; - if (!Method->hasRelatedResultType() || - CGF.getContext().hasSameType(ExpT, Method->getReturnType()) || - !Result.isScalar()) + // If the converted types are the same, we're done. + llvm::Type *ExpLLVMTy = CGF.ConvertType(ExpT); + if (ExpLLVMTy == Result.getScalarVal()->getType()) return Result; - - // We have applied a related result type. Cast the rvalue appropriately. + + // We have applied a substitution. Cast the rvalue appropriately. return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(), - CGF.ConvertType(ExpT))); + ExpLLVMTy)); } /// Decide whether to extend the lifetime of the receiver of a @@ -449,7 +447,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Builder.CreateStore(newSelf, selfAddr); } - return AdjustRelatedResultType(*this, E->getType(), method, result); + return AdjustObjCObjectType(*this, E->getType(), result); } namespace { @@ -2011,7 +2009,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) { // Call the marker asm if we made one, which we do only at -O0. if (marker) - Builder.CreateCall(marker, {}); + Builder.CreateCall(marker); return emitARCValueOperation(*this, value, CGM.getARCEntrypoints().objc_retainAutoreleasedReturnValue, diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp index 5290a87cebf2..2ac6bb2e8a93 100644 --- a/lib/CodeGen/CGObjCRuntime.cpp +++ b/lib/CodeGen/CGObjCRuntime.cpp @@ -134,7 +134,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, CGF.CGM.getContext().toBits(StorageSize), - Alignment.getQuantity())); + CharUnits::fromQuantity(0))); V = CGF.Builder.CreateBitCast(V, llvm::Type::getIntNPtrTy(CGF.getLLVMContext(), @@ -160,7 +160,7 @@ namespace { void Emit(CodeGenFunction &CGF, Flags flags) override { if (!MightThrow) { - CGF.Builder.CreateCall(Fn, {})->setDoesNotThrow(); + CGF.Builder.CreateCall(Fn)->setDoesNotThrow(); return; } diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 534d148209ba..81488398bb86 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -537,7 +537,7 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) { break; } case OMPRTL__kmpc_barrier: { - // Build void __kmpc_cancel_barrier(ident_t *loc, kmp_int32 global_tid); + // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid); llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); @@ -829,6 +829,15 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) { RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_cancellationpoint"); break; } + case OMPRTL__kmpc_cancel: { + // Build kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid, + // kmp_int32 cncl_kind) + llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.IntTy}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_cancel"); + break; + } } return RTLFn; } @@ -923,6 +932,8 @@ llvm::Constant *CGOpenMPRuntime::createDispatchNextFunction(unsigned IVSize, llvm::Constant * CGOpenMPRuntime::getOrCreateThreadPrivateCache(const VarDecl *VD) { + assert(!CGM.getLangOpts().OpenMPUseTLS || + !CGM.getContext().getTargetInfo().isTLSSupported()); // Lookup the entry, lazily creating it if necessary. return getOrCreateInternalVariable(CGM.Int8PtrPtrTy, Twine(CGM.getMangledName(VD)) + ".cache."); @@ -932,6 +943,10 @@ llvm::Value *CGOpenMPRuntime::getAddrOfThreadPrivate(CodeGenFunction &CGF, const VarDecl *VD, llvm::Value *VDAddr, SourceLocation Loc) { + if (CGM.getLangOpts().OpenMPUseTLS && + CGM.getContext().getTargetInfo().isTLSSupported()) + return VDAddr; + auto VarTy = VDAddr->getType()->getPointerElementType(); llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), CGF.Builder.CreatePointerCast(VDAddr, CGM.Int8PtrTy), @@ -961,6 +976,10 @@ void CGOpenMPRuntime::emitThreadPrivateVarInit( llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition( const VarDecl *VD, llvm::Value *VDAddr, SourceLocation Loc, bool PerformInit, CodeGenFunction *CGF) { + if (CGM.getLangOpts().OpenMPUseTLS && + CGM.getContext().getTargetInfo().isTLSSupported()) + return nullptr; + VD = VD->getDefinition(CGM.getContext()); if (VD && ThreadPrivateWithDefinition.count(VD) == 0) { ThreadPrivateWithDefinition.insert(VD); @@ -2723,18 +2742,18 @@ void CGOpenMPRuntime::emitInlinedDirective(CodeGenFunction &CGF, CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr); } -void CGOpenMPRuntime::emitCancellationPointCall( - CodeGenFunction &CGF, SourceLocation Loc, - OpenMPDirectiveKind CancelRegion) { - // Build call kmp_int32 OMPRTL__kmpc_cancellationpoint(ident_t *loc, kmp_int32 - // global_tid, kmp_int32 cncl_kind); - enum { - CancelNoreq = 0, - CancelParallel = 1, - CancelLoop = 2, - CancelSections = 3, - CancelTaskgroup = 4 - } CancelKind = CancelNoreq; +namespace { +enum RTCancelKind { + CancelNoreq = 0, + CancelParallel = 1, + CancelLoop = 2, + CancelSections = 3, + CancelTaskgroup = 4 +}; +} + +static RTCancelKind getCancellationKind(OpenMPDirectiveKind CancelRegion) { + RTCancelKind CancelKind = CancelNoreq; if (CancelRegion == OMPD_parallel) CancelKind = CancelParallel; else if (CancelRegion == OMPD_for) @@ -2745,14 +2764,22 @@ void CGOpenMPRuntime::emitCancellationPointCall( assert(CancelRegion == OMPD_taskgroup); CancelKind = CancelTaskgroup; } + return CancelKind; +} + +void CGOpenMPRuntime::emitCancellationPointCall( + CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind CancelRegion) { + // Build call kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32 + // global_tid, kmp_int32 cncl_kind); if (auto *OMPRegionInfo = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) { auto CancelDest = CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind()); if (CancelDest.isValid()) { - llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), - getThreadID(CGF, Loc), - CGF.Builder.getInt32(CancelKind)}; + llvm::Value *Args[] = { + emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), + CGF.Builder.getInt32(getCancellationKind(CancelRegion))}; // Ignore return result until untied tasks are supported. auto *Result = CGF.EmitRuntimeCall( createRuntimeFunction(OMPRTL__kmpc_cancellationpoint), Args); @@ -2774,3 +2801,36 @@ void CGOpenMPRuntime::emitCancellationPointCall( } } +void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind CancelRegion) { + // Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid, + // kmp_int32 cncl_kind); + if (auto *OMPRegionInfo = + dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) { + auto CancelDest = + CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind()); + if (CancelDest.isValid()) { + llvm::Value *Args[] = { + emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), + CGF.Builder.getInt32(getCancellationKind(CancelRegion))}; + // Ignore return result until untied tasks are supported. + auto *Result = + CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_cancel), Args); + // if (__kmpc_cancel()) { + // __kmpc_cancel_barrier(); + // exit from construct; + // } + auto *ExitBB = CGF.createBasicBlock(".cancel.exit"); + auto *ContBB = CGF.createBasicBlock(".cancel.continue"); + auto *Cmp = CGF.Builder.CreateIsNotNull(Result); + CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB); + CGF.EmitBlock(ExitBB); + // __kmpc_cancel_barrier(); + emitBarrierCall(CGF, Loc, OMPD_unknown, /*CheckForCancel=*/false); + // exit from construct; + CGF.EmitBranchThroughCleanup(CancelDest); + CGF.EmitBlock(ContBB, /*IsFinished=*/true); + } + } +} + diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h index 76bb3ae35931..44bc8a139b15 100644 --- a/lib/CodeGen/CGOpenMPRuntime.h +++ b/lib/CodeGen/CGOpenMPRuntime.h @@ -151,6 +151,9 @@ private: // Call to kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32 // global_tid, kmp_int32 cncl_kind); OMPRTL__kmpc_cancellationpoint, + // Call to kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid, + // kmp_int32 cncl_kind); + OMPRTL__kmpc_cancel, }; /// \brief Values for bit flags used in the ident_t to describe the fields. @@ -698,6 +701,12 @@ public: virtual void emitCancellationPointCall(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind CancelRegion); + + /// \brief Emit code for 'cancel' construct. + /// \param CancelRegion Region kind for which the cancel must be emitted. + /// + virtual void emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind CancelRegion); }; } // namespace CodeGen diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index c15f9fde06f5..d4ad33e3345e 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -78,16 +78,16 @@ struct CGBitFieldInfo { /// bitfield. unsigned StorageSize; - /// The alignment which should be used when accessing the bitfield. - unsigned StorageAlignment; + /// The offset of the bitfield storage from the start of the struct. + CharUnits StorageOffset; CGBitFieldInfo() - : Offset(), Size(), IsSigned(), StorageSize(), StorageAlignment() {} + : Offset(), Size(), IsSigned(), StorageSize(), StorageOffset() {} CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned, - unsigned StorageSize, unsigned StorageAlignment) + unsigned StorageSize, CharUnits StorageOffset) : Offset(Offset), Size(Size), IsSigned(IsSigned), - StorageSize(StorageSize), StorageAlignment(StorageAlignment) {} + StorageSize(StorageSize), StorageOffset(StorageOffset) {} void print(raw_ostream &OS) const; void dump() const; @@ -99,7 +99,7 @@ struct CGBitFieldInfo { const FieldDecl *FD, uint64_t Offset, uint64_t Size, uint64_t StorageSize, - uint64_t StorageAlignment); + CharUnits StorageOffset); }; /// CGRecordLayout - This class handles struct and union layout info while diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index c89d5cc3892a..f91ecebd0926 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -228,11 +228,7 @@ void CGRecordLowering::setBitFieldInfo( Info.Offset = (unsigned)(getFieldBitOffset(FD) - Context.toBits(StartOffset)); Info.Size = FD->getBitWidthValue(Context); Info.StorageSize = (unsigned)DataLayout.getTypeAllocSizeInBits(StorageType); - // Here we calculate the actual storage alignment of the bits. E.g if we've - // got an alignment >= 2 and the bitfield starts at offset 6 we've got an - // alignment of 2. - Info.StorageAlignment = - Layout.getAlignment().alignmentAtOffset(StartOffset).getQuantity(); + Info.StorageOffset = StartOffset; if (Info.Size > Info.StorageSize) Info.Size = Info.StorageSize; // Reverse the bit offsets for big endian machines. Because we represent @@ -651,7 +647,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, const FieldDecl *FD, uint64_t Offset, uint64_t Size, uint64_t StorageSize, - uint64_t StorageAlignment) { + CharUnits StorageOffset) { // This function is vestigial from CGRecordLayoutBuilder days but is still // used in GCObjCRuntime.cpp. That usage has a "fixme" attached to it that // when addressed will allow for the removal of this function. @@ -683,7 +679,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, Offset = StorageSize - (Offset + Size); } - return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageAlignment); + return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageOffset); } CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, @@ -856,7 +852,7 @@ void CGBitFieldInfo::print(raw_ostream &OS) const { << " Size:" << Size << " IsSigned:" << IsSigned << " StorageSize:" << StorageSize - << " StorageAlignment:" << StorageAlignment << ">"; + << " StorageOffset:" << StorageOffset.getQuantity() << ">"; } void CGBitFieldInfo::dump() const { diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index a12f29534bfe..7a0b8a35be01 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -1852,6 +1852,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { std::vector<llvm::Value*> InOutArgs; std::vector<llvm::Type*> InOutArgTypes; + // An inline asm can be marked readonly if it meets the following conditions: + // - it doesn't have any sideeffects + // - it doesn't clobber memory + // - it doesn't return a value by-reference + // It can be marked readnone if it doesn't have any input memory constraints + // in addition to meeting the conditions listed above. + bool ReadOnly = true, ReadNone = true; + for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; @@ -1915,6 +1923,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { Args.push_back(Dest.getAddress()); Constraints += "=*"; Constraints += OutputConstraint; + ReadOnly = ReadNone = false; } if (Info.isReadWrite()) { @@ -1959,6 +1968,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; + if (Info.allowsMemory()) + ReadNone = false; + if (!Constraints.empty()) Constraints += ','; @@ -2023,7 +2035,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { StringRef Clobber = S.getClobber(i); - if (Clobber != "memory" && Clobber != "cc") + if (Clobber == "memory") + ReadOnly = ReadNone = false; + else if (Clobber != "cc") Clobber = getTarget().getNormalizedGCCRegisterName(Clobber); if (!Constraints.empty()) @@ -2063,6 +2077,16 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { Result->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoUnwind); + // Attach readnone and readonly attributes. + if (!HasSideEffect) { + if (ReadNone) + Result->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::ReadNone); + else if (ReadOnly) + Result->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::ReadOnly); + } + // Slap the source location of the inline asm into a !srcloc metadata on the // call. if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) { diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index b021c1275318..a1f093a8d866 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -2108,7 +2108,8 @@ void CodeGenFunction::EmitOMPCancellationPointDirective( } void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) { - llvm_unreachable("CodeGen for 'omp cancel' is not supported yet."); + CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(), + S.getCancelRegion()); } CodeGenFunction::JumpDest diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 969629fb5845..e36051c2053b 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -364,7 +364,7 @@ void CodeGenFunction::EmitMustTailThunk(const CXXMethodDecl *MD, FinishFunction(); } -void CodeGenFunction::GenerateThunk(llvm::Function *Fn, +void CodeGenFunction::generateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, GlobalDecl GD, const ThunkInfo &Thunk) { StartThunk(Fn, GD, FnInfo); @@ -376,13 +376,6 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, // Make the call and return the result. EmitCallAndReturnForThunk(Callee, &Thunk); - - // Set the right linkage. - CGM.setFunctionLinkage(GD, Fn); - - // Set the right visibility. - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - setThunkVisibility(CGM, MD, Thunk, Fn); } void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, @@ -455,11 +448,17 @@ void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk); } else { // Normal thunk body generation. - CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk); + CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, Thunk); } + CGM.setFunctionLinkage(GD, ThunkFn); CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable, GD, !Thunk.Return.isEmpty()); + + // Set the right visibility. + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + setThunkVisibility(CGM, MD, Thunk, ThunkFn); + if (CGM.supportsCOMDAT() && ThunkFn->isWeakForLinker()) ThunkFn->setComdat(CGM.getModule().getOrInsertComdat(ThunkFn->getName())); } @@ -841,6 +840,11 @@ void CodeGenModule::EmitDeferredVTables() { DeferredVTables.clear(); } +bool CodeGenModule::IsCFIBlacklistedRecord(const CXXRecordDecl *RD) { + // FIXME: Make this user configurable. + return RD->isInStdNamespace(); +} + void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, const VTableLayout &VTLayout) { if (!LangOpts.Sanitize.has(SanitizerKind::CFIVCall) && @@ -855,8 +859,7 @@ void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, std::vector<llvm::MDTuple *> BitsetEntries; // Create a bit set entry for each address point. for (auto &&AP : VTLayout.getAddressPoints()) { - // FIXME: Add blacklisting scheme. - if (AP.first.getBase()->isInStdNamespace()) + if (IsCFIBlacklistedRecord(AP.first.getBase())) continue; BitsetEntries.push_back(CreateVTableBitSetEntry( diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 5a060b30808b..10bda76b6b69 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -10,6 +10,7 @@ set(LLVM_LINK_COMPONENTS Linker MC ObjCARCOpts + Object ProfileData ScalarOpts Support @@ -71,6 +72,7 @@ add_clang_library(clangCodeGen ItaniumCXXABI.cpp MicrosoftCXXABI.cpp ModuleBuilder.cpp + ObjectFilePCHContainerOperations.cpp SanitizerMetadata.cpp TargetInfo.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 1fca466e9244..ec3c75ccd257 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -45,12 +45,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr), NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr), ExceptionSlot(nullptr), EHSelectorSlot(nullptr), - AbnormalTerminationSlot(nullptr), SEHPointersDecl(nullptr), - DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false), - DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm), - SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr), - UnreachableBlock(nullptr), NumReturnExprs(0), NumSimpleReturnExprs(0), - CXXABIThisDecl(nullptr), CXXABIThisValue(nullptr), CXXThisValue(nullptr), + DebugInfo(CGM.getModuleDebugInfo()), + DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(nullptr), + PGO(cgm), SwitchInsn(nullptr), SwitchWeights(nullptr), + CaseRangeBlock(nullptr), UnreachableBlock(nullptr), NumReturnExprs(0), + NumSimpleReturnExprs(0), CXXABIThisDecl(nullptr), + CXXABIThisValue(nullptr), CXXThisValue(nullptr), CXXDefaultInitExprThis(nullptr), CXXStructorImplicitParamDecl(nullptr), CXXStructorImplicitParamValue(nullptr), OutermostConditional(nullptr), CurLexicalScope(nullptr), TerminateLandingPad(nullptr), @@ -284,7 +284,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { Builder.ClearInsertionPoint(); } - // If some of our locals escaped, insert a call to llvm.frameescape in the + // If some of our locals escaped, insert a call to llvm.localescape in the // entry block. if (!EscapedLocals.empty()) { // Invert the map from local to index into a simple vector. There should be @@ -294,7 +294,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { for (auto &Pair : EscapedLocals) EscapeArgs[Pair.second] = Pair.first; llvm::Function *FrameEscapeFn = llvm::Intrinsic::getDeclaration( - &CGM.getModule(), llvm::Intrinsic::frameescape); + &CGM.getModule(), llvm::Intrinsic::localescape); CGBuilderTy(AllocaInsertPt).CreateCall(FrameEscapeFn, EscapeArgs); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index a74c474232c8..f2bc402f8b25 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -324,11 +324,13 @@ public: /// write the current selector value into this alloca. llvm::AllocaInst *EHSelectorSlot; - llvm::AllocaInst *AbnormalTerminationSlot; + /// A stack of exception code slots. Entering an __except block pushes a slot + /// on the stack and leaving pops one. The __exception_code() intrinsic loads + /// a value from the top of the stack. + SmallVector<llvm::Value *, 1> SEHCodeSlotStack; - /// The implicit parameter to SEH filter functions of type - /// 'EXCEPTION_POINTERS*'. - ImplicitParamDecl *SEHPointersDecl; + /// Value returned by __exception_info intrinsic. + llvm::Value *SEHInfo = nullptr; /// Emits a landing pad for the current EH stack. llvm::BasicBlock *EmitLandingPad(); @@ -886,7 +888,7 @@ private: DeclMapTy LocalDeclMap; /// Track escaped local variables with auto storage. Used during SEH - /// outlining to produce a call to llvm.frameescape. + /// outlining to produce a call to llvm.localescape. llvm::DenseMap<llvm::AllocaInst *, int> EscapedLocals; /// LabelMap - This keeps track of the LLVM basic block for each C label. @@ -1292,8 +1294,8 @@ public: void EmitMustTailThunk(const CXXMethodDecl *MD, llvm::Value *AdjustedThisPtr, llvm::Value *Callee); - /// GenerateThunk - Generate a thunk for the given method. - void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, + /// Generate a thunk for the given method. + void generateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, GlobalDecl GD, const ThunkInfo &Thunk); llvm::Function *GenerateVarArgsThunk(llvm::Function *Fn, @@ -2048,8 +2050,7 @@ public: void EnterSEHTryStmt(const SEHTryStmt &S); void ExitSEHTryStmt(const SEHTryStmt &S); - void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, StringRef Name, - QualType RetTy, FunctionArgList &Args, + void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, bool IsFilter, const Stmt *OutlinedStmt); llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, @@ -2058,16 +2059,27 @@ public: llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, const SEHFinallyStmt &Finally); - void EmitSEHExceptionCodeSave(); + void EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF, + llvm::Value *ParentFP, + llvm::Value *EntryEBP); llvm::Value *EmitSEHExceptionCode(); llvm::Value *EmitSEHExceptionInfo(); llvm::Value *EmitSEHAbnormalTermination(); /// Scan the outlined statement for captures from the parent function. For /// each capture, mark the capture as escaped and emit a call to - /// llvm.framerecover. Insert the framerecover result into the LocalDeclMap. + /// llvm.localrecover. Insert the localrecover result into the LocalDeclMap. void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt, - llvm::Value *ParentFP); + bool IsFilter); + + /// Recovers the address of a local in a parent function. ParentVar is the + /// address of the variable used in the immediate parent function. It can + /// either be an alloca or a call to llvm.localrecover if there are nested + /// outlined functions. ParentFP is the frame pointer of the outermost parent + /// frame. + llvm::Value *recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, + llvm::Value *ParentVar, + llvm::Value *ParentFP); void EmitCXXForRangeStmt(const CXXForRangeStmt &S, ArrayRef<const Attr *> Attrs = None); @@ -2931,6 +2943,26 @@ private: SourceLocation Loc); public: +#ifndef NDEBUG + // Determine whether the given argument is an Objective-C method + // that may have type parameters in its signature. + static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) { + const DeclContext *dc = method->getDeclContext(); + if (const ObjCInterfaceDecl *classDecl= dyn_cast<ObjCInterfaceDecl>(dc)) { + return classDecl->getTypeParamListAsWritten(); + } + + if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) { + return catDecl->getTypeParamList(); + } + + return false; + } + + template<typename T> + static bool isObjCMethodWithTypeParams(const T *) { return false; } +#endif + /// EmitCallArgs - Emit call arguments for a function. template <typename T> void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo, @@ -2944,18 +2976,25 @@ public: assert((ParamsToSkip == 0 || CallArgTypeInfo) && "Can't skip parameters if type info is not provided"); if (CallArgTypeInfo) { +#ifndef NDEBUG + bool isGenericMethod = isObjCMethodWithTypeParams(CallArgTypeInfo); +#endif + // First, use the argument types that the type info knows about for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip, E = CallArgTypeInfo->param_type_end(); I != E; ++I, ++Arg) { assert(Arg != ArgEnd && "Running over edge of argument list!"); - assert( - ((*I)->isVariablyModifiedType() || - getContext() - .getCanonicalType((*I).getNonReferenceType()) - .getTypePtr() == - getContext().getCanonicalType(Arg->getType()).getTypePtr()) && - "type mismatch in call argument!"); + assert((isGenericMethod || + ((*I)->isVariablyModifiedType() || + (*I).getNonReferenceType()->isObjCRetainableType() || + getContext() + .getCanonicalType((*I).getNonReferenceType()) + .getTypePtr() == + getContext() + .getCanonicalType(Arg->getType()) + .getTypePtr())) && + "type mismatch in call argument!"); ArgTypes.push_back(*I); } } diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index b905bd2b36bf..a179ad42eac1 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1262,6 +1262,11 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) { // Implicit template instantiations may change linkage if they are later // explicitly instantiated, so they should not be emitted eagerly. return false; + // If OpenMP is enabled and threadprivates must be generated like TLS, delay + // codegen for global variables, because they may be marked as threadprivate. + if (LangOpts.OpenMP && LangOpts.OpenMPUseTLS && + getContext().getTargetInfo().isTLSSupported() && isa<VarDecl>(Global)) + return false; return true; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 9a295feaffa4..dd167a29f5ac 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -1126,6 +1126,10 @@ public: /// \param D Threadprivate declaration. void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); + /// Returns whether the given record is blacklisted from control flow + /// integrity checks. + bool IsCFIBlacklistedRecord(const CXXRecordDecl *RD); + /// Emit bit set entries for the given vtable using the given layout if /// vptr CFI is enabled. void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index fa86e52ec804..70af69b76457 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -2095,7 +2095,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( CGBuilderTy Builder(Entry); if (InitIsInitFunc) { if (Init) - Builder.CreateCall(Init, {}); + Builder.CreateCall(Init); } else { // Don't know whether we have an init function. Call it if it exists. llvm::Value *Have = Builder.CreateIsNotNull(Init); @@ -2104,7 +2104,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( Builder.CreateCondBr(Have, InitBB, ExitBB); Builder.SetInsertPoint(InitBB); - Builder.CreateCall(Init, {}); + Builder.CreateCall(Init); Builder.CreateBr(ExitBB); Builder.SetInsertPoint(ExitBB); @@ -2133,7 +2133,7 @@ LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty); llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Val); - Val = CGF.Builder.CreateCall(Wrapper, {}); + Val = CGF.Builder.CreateCall(Wrapper); LValue LV; if (VD->getType()->isReferenceType()) @@ -3620,7 +3620,7 @@ static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) { catchCall->setCallingConv(CGM.getRuntimeCC()); // Call std::terminate(). - llvm::CallInst *termCall = builder.CreateCall(CGM.getTerminateFn(), {}); + llvm::CallInst *termCall = builder.CreateCall(CGM.getTerminateFn()); termCall->setDoesNotThrow(); termCall->setDoesNotReturn(); termCall->setCallingConv(CGM.getRuntimeCC()); diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index d149df63c9e4..3433990e1288 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1466,20 +1466,27 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info, llvm::NamedMDNode *BitsetsMD = CGM.getModule().getOrInsertNamedMetadata("llvm.bitsets"); - CharUnits PointerWidth = getContext().toCharUnitsFromBits( - getContext().getTargetInfo().getPointerWidth(0)); - // FIXME: Add blacklisting scheme. + // The location of the first virtual function pointer in the virtual table, + // aka the "address point" on Itanium. This is at offset 0 if RTTI is + // disabled, or sizeof(void*) if RTTI is enabled. + CharUnits AddressPoint = + getContext().getLangOpts().RTTIData + ? getContext().toCharUnitsFromBits( + getContext().getTargetInfo().getPointerWidth(0)) + : CharUnits::Zero(); if (Info->PathToBaseWithVPtr.empty()) { - BitsetsMD->addOperand( - CGM.CreateVTableBitSetEntry(VTable, PointerWidth, RD)); + if (!CGM.IsCFIBlacklistedRecord(RD)) + BitsetsMD->addOperand( + CGM.CreateVTableBitSetEntry(VTable, AddressPoint, RD)); return; } // Add a bitset entry for the least derived base belonging to this vftable. - BitsetsMD->addOperand(CGM.CreateVTableBitSetEntry( - VTable, PointerWidth, Info->PathToBaseWithVPtr.back())); + if (!CGM.IsCFIBlacklistedRecord(Info->PathToBaseWithVPtr.back())) + BitsetsMD->addOperand(CGM.CreateVTableBitSetEntry( + VTable, AddressPoint, Info->PathToBaseWithVPtr.back())); // Add a bitset entry for each derived class that is laid out at the same // offset as the least derived base. @@ -1497,14 +1504,15 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info, Offset = VBI->second.VBaseOffset; if (!Offset.isZero()) return; - BitsetsMD->addOperand( - CGM.CreateVTableBitSetEntry(VTable, PointerWidth, DerivedRD)); + if (!CGM.IsCFIBlacklistedRecord(DerivedRD)) + BitsetsMD->addOperand( + CGM.CreateVTableBitSetEntry(VTable, AddressPoint, DerivedRD)); } // Finally do the same for the most derived class. - if (Info->FullOffsetInMDC.isZero()) + if (Info->FullOffsetInMDC.isZero() && !CGM.IsCFIBlacklistedRecord(RD)) BitsetsMD->addOperand( - CGM.CreateVTableBitSetEntry(VTable, PointerWidth, RD)); + CGM.CreateVTableBitSetEntry(VTable, AddressPoint, RD)); } void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, @@ -1707,7 +1715,7 @@ static const CXXRecordDecl *getClassAtVTableLocation(ASTContext &Ctx, for (auto &&B : RD->bases()) { const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl(); CharUnits BaseOffset = Layout.getBaseClassOffset(Base); - if (BaseOffset <= Offset && BaseOffset > MaxBaseOffset) { + if (BaseOffset <= Offset && BaseOffset >= MaxBaseOffset) { MaxBase = Base; MaxBaseOffset = BaseOffset; } @@ -1715,7 +1723,7 @@ static const CXXRecordDecl *getClassAtVTableLocation(ASTContext &Ctx, for (auto &&B : RD->vbases()) { const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl(); CharUnits BaseOffset = Layout.getVBaseClassOffset(Base); - if (BaseOffset <= Offset && BaseOffset > MaxBaseOffset) { + if (BaseOffset <= Offset && BaseOffset >= MaxBaseOffset) { MaxBase = Base; MaxBaseOffset = BaseOffset; } diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp new file mode 100644 index 000000000000..8f04e06988d8 --- /dev/null +++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp @@ -0,0 +1,193 @@ +//===--- ObjectFilePCHContainerOperations.cpp -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/CodeGen/ObjectFilePCHContainerOperations.h" +#include "CGDebugInfo.h" +#include "CodeGenModule.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/CodeGen/BackendUtil.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "clang/Serialization/ASTWriter.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/TargetRegistry.h" +#include <memory> +using namespace clang; + +#define DEBUG_TYPE "pchcontainer" + +namespace { +class PCHContainerGenerator : public ASTConsumer { + DiagnosticsEngine &Diags; + const std::string MainFileName; + ASTContext *Ctx; + const HeaderSearchOptions &HeaderSearchOpts; + const PreprocessorOptions &PreprocessorOpts; + CodeGenOptions CodeGenOpts; + const TargetOptions TargetOpts; + const LangOptions LangOpts; + std::unique_ptr<llvm::LLVMContext> VMContext; + std::unique_ptr<llvm::Module> M; + std::unique_ptr<CodeGen::CodeGenModule> Builder; + raw_pwrite_stream *OS; + std::shared_ptr<PCHBuffer> Buffer; + +public: + PCHContainerGenerator(DiagnosticsEngine &diags, + const HeaderSearchOptions &HSO, + const PreprocessorOptions &PPO, const TargetOptions &TO, + const LangOptions &LO, const std::string &MainFileName, + const std::string &OutputFileName, + raw_pwrite_stream *OS, + std::shared_ptr<PCHBuffer> Buffer) + : Diags(diags), HeaderSearchOpts(HSO), PreprocessorOpts(PPO), + TargetOpts(TO), LangOpts(LO), OS(OS), Buffer(Buffer) { + // The debug info output isn't affected by CodeModel and + // ThreadModel, but the backend expects them to be nonempty. + CodeGenOpts.CodeModel = "default"; + CodeGenOpts.ThreadModel = "single"; + CodeGenOpts.setDebugInfo(CodeGenOptions::FullDebugInfo); + CodeGenOpts.SplitDwarfFile = OutputFileName; + } + + virtual ~PCHContainerGenerator() {} + + void Initialize(ASTContext &Context) override { + Ctx = &Context; + VMContext.reset(new llvm::LLVMContext()); + M.reset(new llvm::Module(MainFileName, *VMContext)); + M->setDataLayout(Ctx->getTargetInfo().getTargetDescription()); + Builder.reset(new CodeGen::CodeGenModule(*Ctx, HeaderSearchOpts, + PreprocessorOpts, CodeGenOpts, *M, + M->getDataLayout(), Diags)); + } + + /// Emit a container holding the serialized AST. + void HandleTranslationUnit(ASTContext &Ctx) override { + assert(M && VMContext && Builder); + // Delete these on function exit. + std::unique_ptr<llvm::LLVMContext> VMContext = std::move(this->VMContext); + std::unique_ptr<llvm::Module> M = std::move(this->M); + std::unique_ptr<CodeGen::CodeGenModule> Builder = std::move(this->Builder); + + if (Diags.hasErrorOccurred()) + return; + + M->setTargetTriple(Ctx.getTargetInfo().getTriple().getTriple()); + M->setDataLayout(Ctx.getTargetInfo().getTargetDescription()); + + // Finalize the Builder. + if (Builder) + Builder->Release(); + + // Ensure the target exists. + std::string Error; + auto Triple = Ctx.getTargetInfo().getTriple(); + if (!llvm::TargetRegistry::lookupTarget(Triple.getTriple(), Error)) + llvm::report_fatal_error(Error); + + // Emit the serialized Clang AST into its own section. + assert(Buffer->IsComplete && "serialization did not complete"); + auto &SerializedAST = Buffer->Data; + auto Size = SerializedAST.size(); + auto Int8Ty = llvm::Type::getInt8Ty(*VMContext); + auto *Ty = llvm::ArrayType::get(Int8Ty, Size); + auto *Data = llvm::ConstantDataArray::getString( + *VMContext, StringRef(SerializedAST.data(), Size), + /*AddNull=*/false); + auto *ASTSym = new llvm::GlobalVariable( + *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage, Data, + "__clang_ast"); + // The on-disk hashtable needs to be aligned. + ASTSym->setAlignment(8); + + // Mach-O also needs a segment name. + if (Triple.isOSBinFormatMachO()) + ASTSym->setSection("__CLANG,__clangast"); + // COFF has an eight character length limit. + else if (Triple.isOSBinFormatCOFF()) + ASTSym->setSection("clangast"); + else + ASTSym->setSection("__clangast"); + + DEBUG({ + // Print the IR for the PCH container to the debug output. + llvm::SmallString<0> Buffer; + llvm::raw_svector_ostream OS(Buffer); + clang::EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts, + Ctx.getTargetInfo().getTargetDescription(), + M.get(), BackendAction::Backend_EmitLL, &OS); + OS.flush(); + llvm::dbgs() << Buffer; + }); + + // Use the LLVM backend to emit the pch container. + clang::EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts, + Ctx.getTargetInfo().getTargetDescription(), + M.get(), BackendAction::Backend_EmitObj, OS); + + // Make sure the pch container hits disk. + OS->flush(); + + // Free the memory for the temporary buffer. + llvm::SmallVector<char, 0> Empty; + SerializedAST = std::move(Empty); + } +}; + +} // namespace + +std::unique_ptr<ASTConsumer> +ObjectFilePCHContainerOperations::CreatePCHContainerGenerator( + DiagnosticsEngine &Diags, const HeaderSearchOptions &HSO, + const PreprocessorOptions &PPO, const TargetOptions &TO, + const LangOptions &LO, const std::string &MainFileName, + const std::string &OutputFileName, llvm::raw_pwrite_stream *OS, + std::shared_ptr<PCHBuffer> Buffer) const { + return llvm::make_unique<PCHContainerGenerator>( + Diags, HSO, PPO, TO, LO, MainFileName, OutputFileName, OS, Buffer); +} + +void ObjectFilePCHContainerOperations::ExtractPCH( + llvm::MemoryBufferRef Buffer, llvm::BitstreamReader &StreamFile) const { + if (auto OF = llvm::object::ObjectFile::createObjectFile(Buffer)) { + auto *Obj = OF.get().get(); + bool IsCOFF = isa<llvm::object::COFFObjectFile>(Obj); + // Find the clang AST section in the container. + for (auto &Section : OF->get()->sections()) { + StringRef Name; + Section.getName(Name); + if ((!IsCOFF && Name == "__clangast") || + ( IsCOFF && Name == "clangast")) { + StringRef Buf; + Section.getContents(Buf); + StreamFile.init((const unsigned char *)Buf.begin(), + (const unsigned char *)Buf.end()); + return; + } + } + } + + // As a fallback, treat the buffer as a raw AST. + StreamFile.init((const unsigned char *)Buffer.getBufferStart(), + (const unsigned char *)Buffer.getBufferEnd()); + return; +} diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index e5ba200e1c57..6226d213b620 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -2073,8 +2073,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, classify(I.getType(), Offset, FieldLo, FieldHi, isNamedArg); Lo = merge(Lo, FieldLo); Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; + if (Lo == Memory || Hi == Memory) { + postMerge(Size, Lo, Hi); + return; + } } } @@ -2094,11 +2096,13 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, // if (Size > 128 && getContext().getTypeSize(i->getType()) != 256) { Lo = Memory; + postMerge(Size, Lo, Hi); return; } // Note, skip this test for bit-fields, see below. if (!BitField && Offset % getContext().getTypeAlign(i->getType())) { Lo = Memory; + postMerge(Size, Lo, Hi); return; } @@ -7095,6 +7099,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types)); case llvm::Triple::mips: case llvm::Triple::mipsel: + if (Triple.getOS() == llvm::Triple::NaCl) + return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types)); return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, true)); case llvm::Triple::mips64: diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 360dbeecabf9..3219dc1cc0e9 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -24,6 +24,8 @@ const char *Action::getClassName(ActionClass AC) { switch (AC) { case InputClass: return "input"; case BindArchClass: return "bind-arch"; + case CudaDeviceClass: return "cuda-device"; + case CudaHostClass: return "cuda-host"; case PreprocessJobClass: return "preprocessor"; case PrecompileJobClass: return "precompiler"; case AnalyzeJobClass: return "analyzer"; @@ -53,6 +55,25 @@ BindArchAction::BindArchAction(std::unique_ptr<Action> Input, const char *_ArchName) : Action(BindArchClass, std::move(Input)), ArchName(_ArchName) {} +void CudaDeviceAction::anchor() {} + +CudaDeviceAction::CudaDeviceAction(std::unique_ptr<Action> Input, + const char *ArchName, bool AtTopLevel) + : Action(CudaDeviceClass, std::move(Input)), GpuArchName(ArchName), + AtTopLevel(AtTopLevel) {} + +void CudaHostAction::anchor() {} + +CudaHostAction::CudaHostAction(std::unique_ptr<Action> Input, + const ActionList &_DeviceActions) + : Action(CudaHostClass, std::move(Input)), DeviceActions(_DeviceActions) {} + +CudaHostAction::~CudaHostAction() { + for (iterator it = DeviceActions.begin(), ie = DeviceActions.end(); it != ie; + ++it) + delete *it; +} + void JobAction::anchor() {} JobAction::JobAction(ActionClass Kind, std::unique_ptr<Action> Input, diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index b9dc35d6219a..180c412bd791 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -174,8 +174,10 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { FinalPhase = phases::Backend; - // -c only runs up to the assembler. - } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) { + // -c and partial CUDA compilations only run up to the assembler. + } else if ((PhaseArg = DAL.getLastArg(options::OPT_c)) || + (PhaseArg = DAL.getLastArg(options::OPT_cuda_device_only)) || + (PhaseArg = DAL.getLastArg(options::OPT_cuda_host_only))) { FinalPhase = phases::Assemble; // Otherwise do everything. @@ -281,6 +283,83 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { return DAL; } +/// \brief Compute target triple from args. +/// +/// This routine provides the logic to compute a target triple from various +/// args passed to the driver and the default triple string. +static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, + const ArgList &Args, + StringRef DarwinArchName = "") { + // FIXME: Already done in Compilation *Driver::BuildCompilation + if (const Arg *A = Args.getLastArg(options::OPT_target)) + DefaultTargetTriple = A->getValue(); + + llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple)); + + // Handle Apple-specific options available here. + if (Target.isOSBinFormatMachO()) { + // If an explict Darwin arch name is given, that trumps all. + if (!DarwinArchName.empty()) { + tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName); + return Target; + } + + // Handle the Darwin '-arch' flag. + if (Arg *A = Args.getLastArg(options::OPT_arch)) { + StringRef ArchName = A->getValue(); + tools::darwin::setTripleTypeForMachOArchName(Target, ArchName); + } + } + + // Handle pseudo-target flags '-mlittle-endian'/'-EL' and + // '-mbig-endian'/'-EB'. + if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, + options::OPT_mbig_endian)) { + if (A->getOption().matches(options::OPT_mlittle_endian)) { + llvm::Triple LE = Target.getLittleEndianArchVariant(); + if (LE.getArch() != llvm::Triple::UnknownArch) + Target = std::move(LE); + } else { + llvm::Triple BE = Target.getBigEndianArchVariant(); + if (BE.getArch() != llvm::Triple::UnknownArch) + Target = std::move(BE); + } + } + + // Skip further flag support on OSes which don't support '-m32' or '-m64'. + if (Target.getArchName() == "tce" || Target.getOS() == llvm::Triple::Minix) + return Target; + + // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. + if (Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, + options::OPT_m32, options::OPT_m16)) { + llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; + + if (A->getOption().matches(options::OPT_m64)) { + AT = Target.get64BitArchVariant().getArch(); + if (Target.getEnvironment() == llvm::Triple::GNUX32) + Target.setEnvironment(llvm::Triple::GNU); + } else if (A->getOption().matches(options::OPT_mx32) && + Target.get64BitArchVariant().getArch() == llvm::Triple::x86_64) { + AT = llvm::Triple::x86_64; + Target.setEnvironment(llvm::Triple::GNUX32); + } else if (A->getOption().matches(options::OPT_m32)) { + AT = Target.get32BitArchVariant().getArch(); + if (Target.getEnvironment() == llvm::Triple::GNUX32) + Target.setEnvironment(llvm::Triple::GNU); + } else if (A->getOption().matches(options::OPT_m16) && + Target.get32BitArchVariant().getArch() == llvm::Triple::x86) { + AT = llvm::Triple::x86; + Target.setEnvironment(llvm::Triple::CODE16); + } + + if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) + Target.setArch(AT); + } + + return Target; +} + Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); @@ -367,7 +446,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); // Owned by the host. - const ToolChain &TC = getToolChain(*UArgs); + const ToolChain &TC = + getToolChain(*UArgs, computeTargetTriple(DefaultTargetTriple, *UArgs)); // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs); @@ -398,6 +478,19 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { return C; } +static void printArgList(raw_ostream &OS, const llvm::opt::ArgList &Args) { + llvm::opt::ArgStringList ASL; + for (const auto *A : Args) + A->render(Args, ASL); + + for (auto I = ASL.begin(), E = ASL.end(); I != E; ++I) { + if (I != ASL.begin()) + OS << ' '; + Command::printArg(OS, *I, true); + } + OS << '\n'; +} + // When clang crashes, produce diagnostic information including the fully // preprocessed source file(s). Request that the developer attach the // diagnostic information to a bug report. @@ -546,7 +639,9 @@ void Driver::generateCompilationDiagnostics(Compilation &C, << "Error generating run script: " + Script + " " + EC.message(); } else { ScriptOS << "# Crash reproducer for " << getClangFullVersion() << "\n" - << "# Original command: "; + << "# Driver args: "; + printArgList(ScriptOS, C.getInputArgs()); + ScriptOS << "# Original command: "; Cmd.Print(ScriptOS, "\n", /*Quote=*/true); Cmd.Print(ScriptOS, "\n", /*Quote=*/true, &CrashInfo); Diag(clang::diag::note_drv_command_failed_diag_msg) << Script; @@ -787,14 +882,6 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } return false; } - - if (C.getArgs().hasArg(options::OPT_print_multi_os_directory)) { - // FIXME: This should print out "lib/../lib", "lib/../lib64", or - // "lib/../lib32" as appropriate for the toolchain. For now, print - // nothing because it's not supported yet. - return false; - } - return true; } @@ -815,9 +902,20 @@ static unsigned PrintActions1(const Compilation &C, Action *A, } else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) { os << '"' << BIA->getArchName() << '"' << ", {" << PrintActions1(C, *BIA->begin(), Ids) << "}"; + } else if (CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) { + os << '"' << CDA->getGpuArchName() << '"' << ", {" + << PrintActions1(C, *CDA->begin(), Ids) << "}"; } else { + ActionList *AL; + if (CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) { + os << "{" << PrintActions1(C, *CHA->begin(), Ids) << "}" + << ", gpu binaries "; + AL = &CHA->getDeviceActions(); + } else + AL = &A->getInputs(); + const char *Prefix = "{"; - for (Action *PreRequisite : *A) { + for (Action *PreRequisite : *AL) { os << Prefix << PrintActions1(C, PreRequisite, Ids); Prefix = ", "; } @@ -1130,6 +1228,93 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } +// For each unique --cuda-gpu-arch= argument creates a TY_CUDA_DEVICE input +// action and then wraps each in CudaDeviceAction paired with appropriate GPU +// arch name. If we're only building device-side code, each action remains +// independent. Otherwise we pass device-side actions as inputs to a new +// CudaHostAction which combines both host and device side actions. +static std::unique_ptr<Action> +buildCudaActions(const Driver &D, const ToolChain &TC, DerivedArgList &Args, + const Arg *InputArg, const types::ID InputType, + std::unique_ptr<Action> Current, ActionList &Actions) { + + assert(InputType == types::TY_CUDA && + "CUDA Actions only apply to CUDA inputs."); + + // Collect all cuda_gpu_arch parameters, removing duplicates. + SmallVector<const char *, 4> GpuArchList; + llvm::StringSet<> GpuArchNames; + for (Arg *A : Args) { + if (A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) { + A->claim(); + if (GpuArchNames.insert(A->getValue()).second) + GpuArchList.push_back(A->getValue()); + } + } + + // Default to sm_20 which is the lowest common denominator for supported GPUs. + // sm_20 code should work correctly, if suboptimally, on all newer GPUs. + if (GpuArchList.empty()) + GpuArchList.push_back("sm_20"); + + // Replicate inputs for each GPU architecture. + Driver::InputList CudaDeviceInputs; + for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) + CudaDeviceInputs.push_back(std::make_pair(types::TY_CUDA_DEVICE, InputArg)); + + // Build actions for all device inputs. + ActionList CudaDeviceActions; + D.BuildActions(TC, Args, CudaDeviceInputs, CudaDeviceActions); + assert(GpuArchList.size() == CudaDeviceActions.size() && + "Failed to create actions for all devices"); + + // Check whether any of device actions stopped before they could generate PTX. + bool PartialCompilation = false; + bool DeviceOnlyCompilation = Args.hasArg(options::OPT_cuda_device_only); + for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) { + if (CudaDeviceActions[i]->getKind() != Action::BackendJobClass) { + PartialCompilation = true; + break; + } + } + + // Figure out what to do with device actions -- pass them as inputs to the + // host action or run each of them independently. + if (PartialCompilation || DeviceOnlyCompilation) { + // In case of partial or device-only compilation results of device actions + // are not consumed by the host action device actions have to be added to + // top-level actions list with AtTopLevel=true and run independently. + + // -o is ambiguous if we have more than one top-level action. + if (Args.hasArg(options::OPT_o) && + (!DeviceOnlyCompilation || GpuArchList.size() > 1)) { + D.Diag(clang::diag::err_drv_output_argument_with_multiple_files); + return nullptr; + } + + for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) + Actions.push_back( + new CudaDeviceAction(std::unique_ptr<Action>(CudaDeviceActions[i]), + GpuArchList[i], /* AtTopLevel */ true)); + // Kill host action in case of device-only compilation. + if (DeviceOnlyCompilation) + Current.reset(nullptr); + return Current; + } else { + // Outputs of device actions during complete CUDA compilation get created + // with AtTopLevel=false and become inputs for the host action. + ActionList DeviceActions; + for (unsigned i = 0, e = GpuArchList.size(); i != e; ++i) + DeviceActions.push_back( + new CudaDeviceAction(std::unique_ptr<Action>(CudaDeviceActions[i]), + GpuArchList[i], /* AtTopLevel */ false)); + // Return a new host action that incorporates original host action and all + // device actions. + return std::unique_ptr<Action>( + new CudaHostAction(std::move(Current), DeviceActions)); + } +} + void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, const InputList &Inputs, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); @@ -1227,6 +1412,25 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, continue; } + phases::ID CudaInjectionPhase; + if (isSaveTempsEnabled()) { + // All phases are done independently, inject GPU blobs during compilation + // phase as that's where we generate glue code to init them. + CudaInjectionPhase = phases::Compile; + } else { + // Assumes that clang does everything up until linking phase, so we inject + // cuda device actions at the last step before linking. Otherwise CUDA + // host action forces preprocessor into a separate invocation. + if (FinalPhase == phases::Link) { + for (auto i = PL.begin(), e = PL.end(); i != e; ++i) { + auto next = i + 1; + if (next != e && *next == phases::Link) + CudaInjectionPhase = *i; + } + } else + CudaInjectionPhase = FinalPhase; + } + // Build the pipeline for this file. std::unique_ptr<Action> Current(new InputAction(*InputArg, InputType)); for (SmallVectorImpl<phases::ID>::iterator i = PL.begin(), e = PL.end(); @@ -1252,6 +1456,15 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args, // Otherwise construct the appropriate action. Current = ConstructPhaseAction(TC, Args, Phase, std::move(Current)); + + if (InputType == types::TY_CUDA && Phase == CudaInjectionPhase && + !Args.hasArg(options::OPT_cuda_host_only)) { + Current = buildCudaActions(*this, TC, Args, InputArg, InputType, + std::move(Current), Actions); + if (!Current) + break; + } + if (Current->getType() == types::TY_Nothing) break; } @@ -1491,7 +1704,13 @@ static const Tool *SelectToolForJob(Compilation &C, bool SaveTemps, if (isa<BackendJobAction>(JA)) { // Check if the compiler supports emitting LLVM IR. assert(Inputs->size() == 1); - JobAction *CompileJA = cast<CompileJobAction>(*Inputs->begin()); + JobAction *CompileJA; + // Extract real host action, if it's a CudaHostAction. + if (CudaHostAction *CudaHA = dyn_cast<CudaHostAction>(*Inputs->begin())) + CompileJA = cast<CompileJobAction>(*CudaHA->begin()); + else + CompileJA = cast<CompileJobAction>(*Inputs->begin()); + const Tool *Compiler = TC->SelectTool(*CompileJA); if (!Compiler) return nullptr; @@ -1525,6 +1744,20 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, InputInfo &Result) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); + InputInfoList CudaDeviceInputInfos; + if (const CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) { + InputInfo II; + // Append outputs of device jobs to the input list. + for (const Action *DA : CHA->getDeviceActions()) { + BuildJobsForAction(C, DA, TC, "", AtTopLevel, + /*MultipleArchs*/ false, LinkingOutput, II); + CudaDeviceInputInfos.push_back(II); + } + // Override current action with a real host compile action and continue + // processing it. + A = *CHA->begin(); + } + if (const InputAction *IA = dyn_cast<InputAction>(A)) { // FIXME: It would be nice to not claim this here; maybe the old scheme of // just using Args was better? @@ -1544,15 +1777,30 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, const char *ArchName = BAA->getArchName(); if (ArchName) - TC = &getToolChain(C.getArgs(), ArchName); + TC = &getToolChain( + C.getArgs(), + computeTargetTriple(DefaultTargetTriple, C.getArgs(), ArchName)); else TC = &C.getDefaultToolChain(); - BuildJobsForAction(C, *BAA->begin(), TC, BAA->getArchName(), AtTopLevel, + BuildJobsForAction(C, *BAA->begin(), TC, ArchName, AtTopLevel, MultipleArchs, LinkingOutput, Result); return; } + if (const CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) { + // Figure out which NVPTX triple to use for device-side compilation based on + // whether host is 64-bit. + llvm::Triple DeviceTriple(C.getDefaultToolChain().getTriple().isArch64Bit() + ? "nvptx64-nvidia-cuda" + : "nvptx-nvidia-cuda"); + BuildJobsForAction(C, *CDA->begin(), + &getToolChain(C.getArgs(), DeviceTriple), + CDA->getGpuArchName(), CDA->isAtTopLevel(), + /*MultipleArchs*/ true, LinkingOutput, Result); + return; + } + const ActionList *Inputs = &A->getInputs(); const JobAction *JA = cast<JobAction>(A); @@ -1584,6 +1832,10 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, if (JA->getType() == types::TY_dSYM) BaseInput = InputInfos[0].getFilename(); + // Append outputs of cuda device jobs to the input list + if (CudaDeviceInputInfos.size()) + InputInfos.append(CudaDeviceInputInfos.begin(), CudaDeviceInputInfos.end()); + // Determine the place to write output to, if any. if (JA->getType() == types::TY_Nothing) Result = InputInfo(A->getType(), BaseInput); @@ -1899,93 +2151,8 @@ std::string Driver::GetTemporaryPath(StringRef Prefix, return Path.str(); } -/// \brief Compute target triple from args. -/// -/// This routine provides the logic to compute a target triple from various -/// args passed to the driver and the default triple string. -static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, - const ArgList &Args, - StringRef DarwinArchName) { - // FIXME: Already done in Compilation *Driver::BuildCompilation - if (const Arg *A = Args.getLastArg(options::OPT_target)) - DefaultTargetTriple = A->getValue(); - - llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple)); - - // Handle Apple-specific options available here. - if (Target.isOSBinFormatMachO()) { - // If an explict Darwin arch name is given, that trumps all. - if (!DarwinArchName.empty()) { - tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName); - return Target; - } - - // Handle the Darwin '-arch' flag. - if (Arg *A = Args.getLastArg(options::OPT_arch)) { - StringRef ArchName = A->getValue(); - tools::darwin::setTripleTypeForMachOArchName(Target, ArchName); - } - } - - // Handle pseudo-target flags '-mlittle-endian'/'-EL' and - // '-mbig-endian'/'-EB'. - if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, - options::OPT_mbig_endian)) { - if (A->getOption().matches(options::OPT_mlittle_endian)) { - if (Target.getArch() == llvm::Triple::mips) - Target.setArch(llvm::Triple::mipsel); - else if (Target.getArch() == llvm::Triple::mips64) - Target.setArch(llvm::Triple::mips64el); - else if (Target.getArch() == llvm::Triple::aarch64_be) - Target.setArch(llvm::Triple::aarch64); - } else { - if (Target.getArch() == llvm::Triple::mipsel) - Target.setArch(llvm::Triple::mips); - else if (Target.getArch() == llvm::Triple::mips64el) - Target.setArch(llvm::Triple::mips64); - else if (Target.getArch() == llvm::Triple::aarch64) - Target.setArch(llvm::Triple::aarch64_be); - } - } - - // Skip further flag support on OSes which don't support '-m32' or '-m64'. - if (Target.getArchName() == "tce" || Target.getOS() == llvm::Triple::Minix) - return Target; - - // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. - if (Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, - options::OPT_m32, options::OPT_m16)) { - llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; - - if (A->getOption().matches(options::OPT_m64)) { - AT = Target.get64BitArchVariant().getArch(); - if (Target.getEnvironment() == llvm::Triple::GNUX32) - Target.setEnvironment(llvm::Triple::GNU); - } else if (A->getOption().matches(options::OPT_mx32) && - Target.get64BitArchVariant().getArch() == llvm::Triple::x86_64) { - AT = llvm::Triple::x86_64; - Target.setEnvironment(llvm::Triple::GNUX32); - } else if (A->getOption().matches(options::OPT_m32)) { - AT = Target.get32BitArchVariant().getArch(); - if (Target.getEnvironment() == llvm::Triple::GNUX32) - Target.setEnvironment(llvm::Triple::GNU); - } else if (A->getOption().matches(options::OPT_m16) && - Target.get32BitArchVariant().getArch() == llvm::Triple::x86) { - AT = llvm::Triple::x86; - Target.setEnvironment(llvm::Triple::CODE16); - } - - if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) - Target.setArch(AT); - } - - return Target; -} - const ToolChain &Driver::getToolChain(const ArgList &Args, - StringRef DarwinArchName) const { - llvm::Triple Target = - computeTargetTriple(DefaultTargetTriple, Args, DarwinArchName); + const llvm::Triple &Target) const { ToolChain *&TC = ToolChains[Target.str()]; if (!TC) { @@ -2050,6 +2217,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, break; } break; + case llvm::Triple::CUDA: + TC = new toolchains::CudaToolChain(*this, Target, Args); + break; default: // Of these targets, Hexagon is the only one that might have // an OS of Linux, in which case it got handled above already. diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index ac18e1eb56a1..42bba56f5d41 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -71,7 +71,7 @@ static int skipArgs(const char *Flag, bool HaveCrashVFS) { return 0; } -static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) { +void Command::printArg(raw_ostream &OS, const char *Arg, bool Quote) { const bool Escape = std::strpbrk(Arg, "\"\\$"); if (!Quote && !Escape) { @@ -146,7 +146,7 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo) const { // Always quote the exe. OS << ' '; - PrintArg(OS, Executable, /*Quote=*/true); + printArg(OS, Executable, /*Quote=*/true); llvm::ArrayRef<const char *> Args = Arguments; llvm::SmallVector<const char *, 128> ArgsRespFile; @@ -175,20 +175,20 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, // Replace the input file name with the crashinfo's file name. OS << ' '; StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename); - PrintArg(OS, ShortName.str().c_str(), Quote); + printArg(OS, ShortName.str().c_str(), Quote); continue; } } OS << ' '; - PrintArg(OS, Arg, Quote); + printArg(OS, Arg, Quote); } if (CrashInfo && HaveCrashVFS) { OS << ' '; - PrintArg(OS, "-ivfsoverlay", Quote); + printArg(OS, "-ivfsoverlay", Quote); OS << ' '; - PrintArg(OS, CrashInfo->VFSPath.str().c_str(), Quote); + printArg(OS, CrashInfo->VFSPath.str().c_str(), Quote); } if (ResponseFile != nullptr) { diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp index f20f58a119f4..c816b29dca23 100644 --- a/lib/Driver/MSVCToolChain.cpp +++ b/lib/Driver/MSVCToolChain.cpp @@ -526,8 +526,5 @@ MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, SanitizerMask MSVCToolChain::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; - // CFI checks are not implemented for MSVC ABI for now. - Res &= ~SanitizerKind::CFI; - Res &= ~SanitizerKind::CFICastStrict; return Res; } diff --git a/lib/Driver/MinGWToolChain.cpp b/lib/Driver/MinGWToolChain.cpp index 606508da6964..197c19e91413 100644 --- a/lib/Driver/MinGWToolChain.cpp +++ b/lib/Driver/MinGWToolChain.cpp @@ -1,5 +1,4 @@ -//===--- MinGWToolChain.cpp - MinGWToolChain Implementation -//-----------------------===// +//===--- MinGWToolChain.cpp - MinGWToolChain Implementation ---------------===// // // The LLVM Compiler Infrastructure // @@ -25,6 +24,9 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); + llvm::SmallString<1024> LibDir; + +#ifdef LLVM_ON_WIN32 if (getDriver().SysRoot.size()) Base = getDriver().SysRoot; else if (llvm::ErrorOr<std::string> GPPName = @@ -34,8 +36,17 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) else Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); Base += llvm::sys::path::get_separator(); - llvm::SmallString<1024> LibDir(Base); + LibDir = Base; llvm::sys::path::append(LibDir, "lib", "gcc"); +#else + if (getDriver().SysRoot.size()) + Base = getDriver().SysRoot; + else + Base = "/usr/"; + LibDir = Base; + llvm::sys::path::append(LibDir, "lib64", "gcc"); +#endif + LibDir += llvm::sys::path::get_separator(); // First look for mingw-w64. @@ -45,6 +56,7 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) llvm::sys::fs::directory_iterator MingW64Entry(LibDir + Arch, EC); if (!EC) { GccLibDir = MingW64Entry->path(); + Ver = llvm::sys::path::filename(GccLibDir); } else { // If mingw-w64 not found, try looking for mingw.org. Arch = "mingw32"; @@ -58,6 +70,10 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) getFilePaths().push_back(GccLibDir); getFilePaths().push_back(Base + "lib"); getFilePaths().push_back(Base + Arch + "lib"); +#ifdef LLVM_ON_UNIX + // For openSUSE. + getFilePaths().push_back(Base + Arch + "sys-root/mingw/lib"); +#endif } bool MinGW::IsIntegratedAssemblerDefault() const { return true; } @@ -117,6 +133,11 @@ void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, llvm::sys::path::append(IncludeDir, "include"); addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str()); IncludeDir += "-fixed"; +#ifdef LLVM_ON_UNIX + // For openSUSE. + addSystemInclude(DriverArgs, CC1Args, + "/usr/x86_64-w64-mingw32/sys-root/mingw/include"); +#endif addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str()); addSystemInclude(DriverArgs, CC1Args, Base + Arch + "include"); addSystemInclude(DriverArgs, CC1Args, Base + "include"); @@ -128,16 +149,27 @@ void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, DriverArgs.hasArg(options::OPT_nostdincxx)) return; - llvm::SmallString<1024> IncludeDir; - for (bool MingW64 : {true, false}) { - if (MingW64) - IncludeDir = Base + Arch; - else - IncludeDir = GccLibDir; - llvm::sys::path::append(IncludeDir, "include", "c++"); - addSystemInclude(DriverArgs, CC1Args, IncludeDir.str()); - IncludeDir += llvm::sys::path::get_separator(); - addSystemInclude(DriverArgs, CC1Args, IncludeDir.str() + Arch); - addSystemInclude(DriverArgs, CC1Args, IncludeDir.str() + "backward"); + // C++ includes may be found in several locations depending on distribution. + // Windows + // ------- + // mingw-w64 mingw-builds: $sysroot/i686-w64-mingw32/include/c++. + // mingw-w64 msys2: $sysroot/include/c++/4.9.2 + // mingw.org: GccLibDir/include/c++ + // + // Linux + // ----- + // openSUSE: GccLibDir/include/c++ + llvm::SmallVector<llvm::SmallString<1024>, 3> CppIncludeBases; + CppIncludeBases.emplace_back(Base); + llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++"); + CppIncludeBases.emplace_back(Base); + llvm::sys::path::append(CppIncludeBases[1], "include", "c++", Ver); + CppIncludeBases.emplace_back(GccLibDir); + llvm::sys::path::append(CppIncludeBases[2], "include", "c++"); + for (auto &CppIncludeBase : CppIncludeBases) { + CppIncludeBase += llvm::sys::path::get_separator(); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); } } diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index 3043481c7132..c3ad8ef9c1ef 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -176,6 +176,7 @@ void SanitizerArgs::clear() { BlacklistFiles.clear(); CoverageFeatures = 0; MsanTrackOrigins = 0; + MsanUseAfterDtor = false; AsanFieldPadding = 0; AsanZeroBaseShadow = false; AsanSharedRuntime = false; @@ -289,8 +290,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // toolchain. We don't have a good way to check the latter, so we just // check if the toolchan supports vptr. if (~Supported & Vptr) { - if (SanitizerMask KindsToDiagnose = - Kinds & ~TrappingKinds & NeedsUbsanCxxRt) { + SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt; + // The runtime library supports the Microsoft C++ ABI, but only well enough + // for CFI. FIXME: Remove this once we support vptr on Windows. + if (TC.getTriple().isOSWindows()) + KindsToDiagnose &= ~CFI; + if (KindsToDiagnose) { SanitizerSet S; S.Mask = KindsToDiagnose; D.Diag(diag::err_drv_unsupported_opt_for_target) @@ -413,6 +418,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } } + MsanUseAfterDtor = + Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor); } // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the @@ -558,6 +565,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (MsanTrackOrigins) CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + llvm::utostr(MsanTrackOrigins))); + + if (MsanUseAfterDtor) + CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-use-after-dtor")); + if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index da020a2b8c9d..e6a1bc9685de 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -151,6 +151,8 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::InputClass: case Action::BindArchClass: + case Action::CudaDeviceClass: + case Action::CudaHostClass: case Action::LipoJobClass: case Action::DsymutilJobClass: case Action::VerifyDebugInfoJobClass: diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index df74b41b0225..15e36a1e6ce0 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -303,6 +303,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args, if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fprofile_generate_EQ) || Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || Args.hasArg(options::OPT_fcreate_profile) || @@ -2337,6 +2338,13 @@ NaCl_TC::NaCl_TC(const Driver &D, const llvm::Triple &Triple, file_paths.push_back(ToolPath + "arm-nacl"); break; } + case llvm::Triple::mipsel: { + file_paths.push_back(FilePath + "mipsel-nacl/lib"); + file_paths.push_back(FilePath + "mipsel-nacl/usr/lib"); + prog_paths.push_back(ProgPath + "bin"); + file_paths.push_back(ToolPath + "mipsel-nacl"); + break; + } default: break; } @@ -2372,6 +2380,9 @@ void NaCl_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, case llvm::Triple::x86_64: llvm::sys::path::append(P, "x86_64-nacl/usr/include"); break; + case llvm::Triple::mipsel: + llvm::sys::path::append(P, "mipsel-nacl/usr/include"); + break; default: return; } @@ -2416,6 +2427,10 @@ void NaCl_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); addSystemInclude(DriverArgs, CC1Args, P.str()); break; + case llvm::Triple::mipsel: + llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + break; default: break; } @@ -2868,6 +2883,7 @@ enum Distro { UbuntuTrusty, UbuntuUtopic, UbuntuVivid, + UbuntuWily, UnknownDistro }; @@ -2882,7 +2898,7 @@ static bool IsDebian(enum Distro Distro) { } static bool IsUbuntu(enum Distro Distro) { - return Distro >= UbuntuHardy && Distro <= UbuntuVivid; + return Distro >= UbuntuHardy && Distro <= UbuntuWily; } static Distro DetectDistro(llvm::Triple::ArchType Arch) { @@ -2911,6 +2927,7 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { .Case("trusty", UbuntuTrusty) .Case("utopic", UbuntuUtopic) .Case("vivid", UbuntuVivid) + .Case("wily", UbuntuWily) .Default(UnknownDistro); return Version; } @@ -3635,6 +3652,65 @@ Tool *DragonFly::buildLinker() const { return new tools::dragonfly::Linker(*this); } +/// Stub for CUDA toolchain. At the moment we don't have assembler or +/// linker and need toolchain mainly to propagate device-side options +/// to CC1. + +CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Linux(D, Triple, Args) {} + +void +CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + Linux::addClangTargetOptions(DriverArgs, CC1Args); + CC1Args.push_back("-fcuda-is-device"); +} + +llvm::opt::DerivedArgList * +CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + const char *BoundArch) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + + for (Arg *A : Args) { + if (A->getOption().matches(options::OPT_Xarch__)) { + // Skip this argument unless the architecture matches BoundArch + if (A->getValue(0) != StringRef(BoundArch)) + continue; + + unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); + unsigned Prev = Index; + std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); + + // If the argument parsing failed or more than one argument was + // consumed, the -Xarch_ argument's parameter tried to consume + // extra arguments. Emit an error and ignore. + // + // We also want to disallow any options which would alter the + // driver behavior; that isn't going to work in our model. We + // use isDriverOption() as an approximation, although things + // like -O4 are going to slip through. + if (!XarchArg || Index > Prev + 1) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) + << A->getAsString(Args); + continue; + } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) + << A->getAsString(Args); + continue; + } + XarchArg->setBaseArg(A); + A = XarchArg.release(); + DAL->AddSynthesizedArg(A); + } + DAL->append(A); + } + + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); + return DAL; +} + /// XCore tool chain XCore::XCore(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 629f90ac79f8..327ff9b13b19 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -552,6 +552,7 @@ protected: private: std::string Base; std::string GccLibDir; + std::string Ver; std::string Arch; mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; mutable std::unique_ptr<tools::gcc::Compiler> Compiler; @@ -698,6 +699,18 @@ private: std::string computeSysRoot() const; }; +class LLVM_LIBRARY_VISIBILITY CudaToolChain : public Linux { +public: + CudaToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, + const char *BoundArch) const override; + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; +}; + class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux { protected: GCCVersion GCCLibAndIncVersion; @@ -746,7 +759,9 @@ public: void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - bool IsIntegratedAssemblerDefault() const override { return false; } + bool IsIntegratedAssemblerDefault() const override { + return getTriple().getArch() == llvm::Triple::mipsel; + } // Get the path to the file containing NaCl's ARM macros. It lives in NaCl_TC // because the AssembleARM tool needs a const char * that it can pass around diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index a2955dbb9e77..8c11992f1f82 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -638,6 +638,8 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<const char *> &Features, bool ForAS) { + bool KernelOrKext = + Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple); if (!ForAS) { // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these @@ -705,6 +707,17 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8_1a) { Features.insert(Features.begin(), "+v8.1a"); } + + // Look for the last occurrence of -mlong-calls or -mno-long-calls. If + // neither options are specified, see if we are compiling for kernel/kext and + // decide whether to pass "+long-calls" based on the OS and its version. + if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, + options::OPT_mno_long_calls)) { + if (A->getOption().matches(options::OPT_mlong_calls)) + Features.push_back("+long-calls"); + } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6))) { + Features.push_back("+long-calls"); + } } void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, @@ -778,11 +791,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, // Kernel code has more strict alignment requirements. if (KernelOrKext) { - if (!Triple.isiOS() || Triple.isOSVersionLT(6)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-long-calls"); - } - CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-strict-align"); @@ -1264,9 +1272,7 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Select the ABI to use. const char *ABIName = nullptr; - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { - ABIName = A->getValue(); - } else if (getToolChain().getTriple().isOSLinux()) + if (getToolChain().getTriple().isOSLinux()) switch (getToolChain().getArch()) { case llvm::Triple::ppc64: { // When targeting a processor that supports QPX, or if QPX is @@ -1291,6 +1297,13 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, break; } + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) + // The ppc64 linux abis are all "altivec" abis by default. Accept and ignore + // the option if given as we don't have backend support for any targets + // that don't use the altivec abi. + if (StringRef(A->getValue()) != "altivec") + ABIName = A->getValue(); + if (ABIName) { CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); @@ -1475,6 +1488,12 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) { return CPUName; } + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + return A->getValue(); + return ""; + case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: { @@ -2028,17 +2047,6 @@ shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, Triple.getArch() == llvm::Triple::arm)); } -// exceptionSettings() exists to share the logic between -cc1 and linker -// invocations. -static bool exceptionSettings(const ArgList &Args, const llvm::Triple &Triple) { - if (Arg *A = Args.getLastArg(options::OPT_fexceptions, - options::OPT_fno_exceptions)) - if (A->getOption().matches(options::OPT_fexceptions)) - return true; - - return false; -} - /// Adds exception related arguments to the driver command arguments. There's a /// master flag, -fexceptions and also language specific flags to enable/disable /// C++ and Objective-C exceptions. This makes it possible to for example @@ -2062,8 +2070,9 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, return; } - // Gather the exception settings from the command line arguments. - bool EH = exceptionSettings(Args, Triple); + // See if the user explicitly enabled exceptions. + bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, + false); // Obj-C exceptions are enabled by default, regardless of -fexceptions. This // is not necessarily sensible, but follows GCC. @@ -2076,8 +2085,11 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, } if (types::isCXX(InputType)) { - bool CXXExceptionsEnabled = - Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU(); + // Disable C++ EH by default on XCore, PS4, and MSVC. + // FIXME: Remove MSVC from this list once things work. + bool CXXExceptionsEnabled = Triple.getArch() != llvm::Triple::xcore && + !Triple.isPS4CPU() && + !Triple.isWindowsMSVCEnvironment(); Arg *ExceptionArg = Args.getLastArg( options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions, options::OPT_fexceptions, options::OPT_fno_exceptions); @@ -2290,6 +2302,7 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args, if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fprofile_generate_EQ) || Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || Args.hasArg(options::OPT_fcreate_profile) || @@ -2723,6 +2736,89 @@ VersionTuple visualstudio::getMSVCVersion(const Driver *D, return VersionTuple(); } +static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, + const InputInfo &Output, const ArgList &Args, + ArgStringList &CmdArgs) { + auto *ProfileGenerateArg = Args.getLastArg( + options::OPT_fprofile_instr_generate, + options::OPT_fprofile_instr_generate_EQ, options::OPT_fprofile_generate, + options::OPT_fprofile_generate_EQ); + + auto *ProfileUseArg = Args.getLastArg( + options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, + options::OPT_fprofile_use, options::OPT_fprofile_use_EQ); + + if (ProfileGenerateArg && ProfileUseArg) + D.Diag(diag::err_drv_argument_not_allowed_with) + << ProfileGenerateArg->getSpelling() + << ProfileUseArg->getSpelling(); + + if (ProfileGenerateArg && + ProfileGenerateArg->getOption().matches( + options::OPT_fprofile_instr_generate_EQ)) + ProfileGenerateArg->render(Args, CmdArgs); + else if (ProfileGenerateArg && + ProfileGenerateArg->getOption().matches( + options::OPT_fprofile_generate_EQ)) { + SmallString<128> Path(ProfileGenerateArg->getValue()); + llvm::sys::path::append(Path, "default.profraw"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-fprofile-instr-generate=") + Path)); + } else + Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate); + + if (ProfileUseArg && + ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) + ProfileUseArg->render(Args, CmdArgs); + else if (ProfileUseArg && + (ProfileUseArg->getOption().matches(options::OPT_fprofile_use_EQ) || + ProfileUseArg->getOption().matches( + options::OPT_fprofile_instr_use))) { + SmallString<128> Path( + ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); + if (Path.empty() || llvm::sys::fs::is_directory(Path)) + llvm::sys::path::append(Path, "default.profdata"); + CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instr-use=") + Path)); + } + + if (Args.hasArg(options::OPT_ftest_coverage) || + Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back("-femit-coverage-notes"); + if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + false) || + Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back("-femit-coverage-data"); + + if (Args.hasArg(options::OPT_fcoverage_mapping) && !ProfileGenerateArg) + D.Diag(diag::err_drv_argument_only_allowed_with) + << "-fcoverage-mapping" + << "-fprofile-instr-generate"; + + if (Args.hasArg(options::OPT_fcoverage_mapping)) + CmdArgs.push_back("-fcoverage-mapping"); + + if (C.getArgs().hasArg(options::OPT_c) || + C.getArgs().hasArg(options::OPT_S)) { + if (Output.isFilename()) { + CmdArgs.push_back("-coverage-file"); + SmallString<128> CoverageFilename; + if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) { + CoverageFilename = FinalOutput->getValue(); + } else { + CoverageFilename = llvm::sys::path::filename(Output.getBaseInput()); + } + if (llvm::sys::path::is_relative(CoverageFilename)) { + SmallString<128> Pwd; + if (!llvm::sys::fs::current_path(Pwd)) { + llvm::sys::path::append(Pwd, CoverageFilename); + CoverageFilename.swap(Pwd); + } + } + CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + } + } +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2736,8 +2832,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getTriple().isWindowsCygwinEnvironment(); bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment(); - assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + // Check number of inputs for sanity. We need at least one input. + assert(Inputs.size() >= 1 && "Must have at least one input."); const InputInfo &Input = Inputs[0]; + // CUDA compilation may have multiple inputs (source file + results of + // device-side compilations). All other jobs are expected to have exactly one + // input. + bool IsCuda = types::isCuda(Input.getType()); + assert((IsCuda || Inputs.size() == 1) && "Unable to handle multiple inputs."); // Invoke ourselves in -cc1 mode. // @@ -2805,6 +2907,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && "Invalid action for clang tool."); + if (JA.getType() == types::TY_LTO_IR || + JA.getType() == types::TY_LTO_BC) { + CmdArgs.push_back("-flto"); + } if (JA.getType() == types::TY_Nothing) { CmdArgs.push_back("-fsyntax-only"); } else if (JA.getType() == types::TY_LLVM_IR || @@ -3520,62 +3626,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); - if ((Args.hasArg(options::OPT_fprofile_instr_generate) || - Args.hasArg(options::OPT_fprofile_instr_generate_EQ)) && - (Args.hasArg(options::OPT_fprofile_instr_use) || - Args.hasArg(options::OPT_fprofile_instr_use_EQ))) - D.Diag(diag::err_drv_argument_not_allowed_with) - << "-fprofile-instr-generate" - << "-fprofile-instr-use"; - - if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_generate_EQ)) - A->render(Args, CmdArgs); - else - Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate); - - if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_use_EQ)) - A->render(Args, CmdArgs); - else if (Args.hasArg(options::OPT_fprofile_instr_use)) - CmdArgs.push_back("-fprofile-instr-use=pgo-data"); - - if (Args.hasArg(options::OPT_ftest_coverage) || - Args.hasArg(options::OPT_coverage)) - CmdArgs.push_back("-femit-coverage-notes"); - if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, - false) || - Args.hasArg(options::OPT_coverage)) - CmdArgs.push_back("-femit-coverage-data"); - - if (Args.hasArg(options::OPT_fcoverage_mapping) && - !(Args.hasArg(options::OPT_fprofile_instr_generate) || - Args.hasArg(options::OPT_fprofile_instr_generate_EQ))) - D.Diag(diag::err_drv_argument_only_allowed_with) - << "-fcoverage-mapping" - << "-fprofile-instr-generate"; - - if (Args.hasArg(options::OPT_fcoverage_mapping)) - CmdArgs.push_back("-fcoverage-mapping"); - - if (C.getArgs().hasArg(options::OPT_c) || - C.getArgs().hasArg(options::OPT_S)) { - if (Output.isFilename()) { - CmdArgs.push_back("-coverage-file"); - SmallString<128> CoverageFilename; - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) { - CoverageFilename = FinalOutput->getValue(); - } else { - CoverageFilename = llvm::sys::path::filename(Output.getBaseInput()); - } - if (llvm::sys::path::is_relative(CoverageFilename)) { - SmallString<128> Pwd; - if (!llvm::sys::fs::current_path(Pwd)) { - llvm::sys::path::append(Pwd, CoverageFilename); - CoverageFilename.swap(Pwd); - } - } - CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); - } - } + addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); // Pass options for controlling the default header search paths. if (Args.hasArg(options::OPT_nostdinc)) { @@ -3915,6 +3966,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, case OMPRT_IOMP5: // Clang can generate useful OpenMP code for these two runtime libraries. CmdArgs.push_back("-fopenmp"); + + // If no option regarding the use of TLS in OpenMP codegeneration is + // given, decide a default based on the target. Otherwise rely on the + // options and pass the right information to the frontend. + if (!Args.hasFlag(options::OPT_fopenmp_use_tls, + options::OPT_fnoopenmp_use_tls, + getToolChain().getArch() == llvm::Triple::ppc || + getToolChain().getArch() == llvm::Triple::ppc64 || + getToolChain().getArch() == llvm::Triple::ppc64le)) + CmdArgs.push_back("-fnoopenmp-use-tls"); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -4070,17 +4131,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-arm-restrict-it"); } - if (TT.getArch() == llvm::Triple::arm || - TT.getArch() == llvm::Triple::thumb) { - if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, - options::OPT_mno_long_calls)) { - if (A->getOption().matches(options::OPT_mlong_calls)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-long-calls"); - } - } - } - // Forward -f options with positive and negative forms; we translate // these by hand. if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { @@ -4172,27 +4222,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fmodule-cache-path specifies where our implicitly-built module files // should be written. - SmallString<128> ModuleCachePath; + SmallString<128> Path; if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) - ModuleCachePath = A->getValue(); + Path = A->getValue(); if (HaveModules) { if (C.isForDiagnostics()) { // When generating crash reports, we want to emit the modules along with // the reproduction sources, so we ignore any provided module path. - ModuleCachePath = Output.getFilename(); - llvm::sys::path::replace_extension(ModuleCachePath, ".cache"); - llvm::sys::path::append(ModuleCachePath, "modules"); - } else if (ModuleCachePath.empty()) { + Path = Output.getFilename(); + llvm::sys::path::replace_extension(Path, ".cache"); + llvm::sys::path::append(Path, "modules"); + } else if (Path.empty()) { // No module path was provided: use the default. llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, - ModuleCachePath); - llvm::sys::path::append(ModuleCachePath, "org.llvm.clang."); - appendUserToPath(ModuleCachePath); - llvm::sys::path::append(ModuleCachePath, "ModuleCache"); + Path); + llvm::sys::path::append(Path, "org.llvm.clang."); + appendUserToPath(Path); + llvm::sys::path::append(Path, "ModuleCache"); } const char Arg[] = "-fmodules-cache-path="; - ModuleCachePath.insert(ModuleCachePath.begin(), Arg, Arg + strlen(Arg)); - CmdArgs.push_back(Args.MakeArgString(ModuleCachePath)); + Path.insert(Path.begin(), Arg, Arg + strlen(Arg)); + CmdArgs.push_back(Args.MakeArgString(Path)); } // When building modules and generating crashdumps, we need to dump a module @@ -4774,14 +4824,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - for (const auto &II : Inputs) { - addDashXForInput(Args, II, CmdArgs); + addDashXForInput(Args, Input, CmdArgs); - if (II.isFilename()) - CmdArgs.push_back(II.getFilename()); - else - II.getInputArg().renderAsInput(Args, CmdArgs); - } + if (Input.isFilename()) + CmdArgs.push_back(Input.getFilename()); + else + Input.getInputArg().renderAsInput(Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_undef); @@ -4819,6 +4867,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(SplitDwarfOut); } + // Host-side cuda compilation receives device-side outputs as Inputs[1...]. + // Include them with -fcuda-include-gpubinary. + if (IsCuda && Inputs.size() > 1) + for (InputInfoList::const_iterator it = std::next(Inputs.begin()), + ie = Inputs.end(); + it != ie; ++it) { + CmdArgs.push_back("-fcuda-include-gpubinary"); + CmdArgs.push_back(it->getFilename()); + } + // Finally add the compile command to the compilation. if (Args.hasArg(options::OPT__SLASH_fallback) && Output.getType() == types::TY_Object && @@ -5005,6 +5063,7 @@ struct EHFlags { /// The default is /EHs-c-, meaning cleanups are disabled. static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { EHFlags EH; + std::vector<std::string> EHArgs = Args.getAllArgValues(options::OPT__SLASH_EH); for (auto EHVal : EHArgs) { @@ -5026,6 +5085,11 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { break; } } + + // FIXME: Disable C++ EH completely, until it becomes more reliable. Users + // can use -Xclang to manually enable C++ EH until then. + EH = EHFlags(); + return EH; } @@ -8199,6 +8263,8 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("armelf_nacl"); else if (Arch == llvm::Triple::x86_64) CmdArgs.push_back("elf_x86_64_nacl"); + else if (Arch == llvm::Triple::mipsel) + CmdArgs.push_back("mipselelf_nacl"); else D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName() << "Native Client"; @@ -8260,6 +8326,13 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // in the group for C++. if (Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) { + // Gold, used by Mips, handles nested groups differently than ld, and + // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a, + // which is not a desired behaviour here. + // See https://sourceware.org/ml/binutils/2015-03/msg00034.html + if (getToolChain().getArch() == llvm::Triple::mipsel) + CmdArgs.push_back("-lnacl"); + CmdArgs.push_back("-lpthread"); } @@ -8270,6 +8343,13 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); + + // Mips needs to create and use pnacl_legacy library that contains + // definitions from bitcode/pnaclmm.c and definitions for + // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset(). + if (getToolChain().getArch() == llvm::Triple::mipsel) + CmdArgs.push_back("-lpnacl_legacy"); + CmdArgs.push_back("--end-group"); } @@ -8863,6 +8943,12 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); + StringRef LinkerName = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "ld"); + if (LinkerName.equals_lower("lld")) { + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("gnu"); + } + if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); @@ -8874,6 +8960,8 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("i386pe"); if (TC.getArch() == llvm::Triple::x86_64) CmdArgs.push_back("i386pep"); + if (TC.getArch() == llvm::Triple::arm) + CmdArgs.push_back("thumb2pe"); if (Args.hasArg(options::OPT_mwindows)) { CmdArgs.push_back("--subsystem"); @@ -8968,10 +9056,8 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lgmon"); - // FIXME: what to do about pthreads library? - // Currently required for OpenMP and posix-threading libgcc, - // does not exists in mingw.org. - //CmdArgs.push_back("-lpthread"); + if (Args.hasArg(options::OPT_pthread)) + CmdArgs.push_back("-lpthread"); // add system libraries if (Args.hasArg(options::OPT_mwindows)) { @@ -8985,7 +9071,7 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--end-group"); - else + else if (!LinkerName.equals_lower("lld")) AddLibGCC(Args, CmdArgs); } @@ -8996,7 +9082,7 @@ void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); } } - const char *Exec = Args.MakeArgString(TC.GetProgramPath("ld")); + const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerName.data())); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); } @@ -9053,7 +9139,9 @@ void XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-v"); - if (exceptionSettings(Args, getToolChain().getTriple())) + // Pass -fexceptions through to the linker if it was present. + if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, + false)) CmdArgs.push_back("-fexceptions"); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 7b281457557b..2085b0124298 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -86,6 +86,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_C: case TY_PP_C: case TY_CL: case TY_CUDA: case TY_PP_CUDA: + case TY_CUDA_DEVICE: case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias: case TY_CXX: case TY_PP_CXX: case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: @@ -122,7 +123,19 @@ bool types::isCXX(ID Id) { case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: - case TY_CUDA: case TY_PP_CUDA: + case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: + return true; + } +} + +bool types::isCuda(ID Id) { + switch (Id) { + default: + return false; + + case TY_CUDA: + case TY_PP_CUDA: + case TY_CUDA_DEVICE: return true; } } @@ -206,10 +219,12 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) { P.push_back(phases::Compile); P.push_back(phases::Backend); } - P.push_back(phases::Assemble); + if (Id != TY_CUDA_DEVICE) + P.push_back(phases::Assemble); } } - if (!onlyPrecompileType(Id)) { + + if (!onlyPrecompileType(Id) && Id != TY_CUDA_DEVICE) { P.push_back(phases::Link); } assert(0 < P.size() && "Not enough phases in list"); diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index ed01d689c590..dd56831a3bc5 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -628,7 +628,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return State.Stack.back().Indent; if (NextNonComment->isOneOf(TT_StartOfName, TT_PointerOrReference) || - Previous.isOneOf(tok::coloncolon, tok::equal)) + Previous.isOneOf(tok::coloncolon, tok::equal, TT_JsTypeColon)) return ContinuationIndent; if (PreviousNonComment && PreviousNonComment->is(tok::colon) && PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral)) @@ -862,6 +862,8 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, unsigned LastSpace = State.Stack.back().LastSpace; bool AvoidBinPacking; bool BreakBeforeParameter = false; + unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, + State.Stack.back().NestedBlockIndent); if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) { if (Current.opensBlockTypeList(Style)) { NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth; @@ -875,6 +877,8 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, Current.isOneOf(TT_ArrayInitializerLSquare, TT_DictLiteral) || Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments || (NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod)); + if (Current.ParameterCount > 1) + NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1); } else { NewIndent = Style.ContinuationIndentWidth + std::max(State.Stack.back().LastSpace, @@ -922,8 +926,6 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, bool NoLineBreak = State.Stack.back().NoLineBreak || (Current.is(TT_TemplateOpener) && State.Stack.back().ContainsUnwrappedBuilder); - unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, - State.Stack.back().NestedBlockIndent); State.Stack.push_back(ParenState(NewIndent, NewIndentLevel, LastSpace, AvoidBinPacking, NoLineBreak)); State.Stack.back().NestedBlockIndent = NestedBlockIndent; diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 2bbe4c63d156..382ae819ebfd 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/YAMLTraits.h" #include <queue> #include <string> @@ -93,6 +94,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> { static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) { IO.enumCase(Value, "Attach", FormatStyle::BS_Attach); IO.enumCase(Value, "Linux", FormatStyle::BS_Linux); + IO.enumCase(Value, "Mozilla", FormatStyle::BS_Mozilla); IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup); IO.enumCase(Value, "Allman", FormatStyle::BS_Allman); IO.enumCase(Value, "GNU", FormatStyle::BS_GNU); @@ -244,6 +246,8 @@ template <> struct MappingTraits<FormatStyle> { Style.IndentWrappedFunctionNames); IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", Style.KeepEmptyLinesAtTheStartOfBlocks); + IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin); + IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd); IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation); IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth); @@ -468,6 +472,8 @@ FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) { ChromiumStyle.BinPackParameters = false; ChromiumStyle.DerivePointerAlignment = false; } + ChromiumStyle.MacroBlockBegin = "^IPC_BEGIN_MESSAGE_MAP$"; + ChromiumStyle.MacroBlockBegin = "^IPC_END_MESSAGE_MAP$"; return ChromiumStyle; } @@ -478,6 +484,7 @@ FormatStyle getMozillaStyle() { MozillaStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_TopLevel; MozillaStyle.AlwaysBreakTemplateDeclarations = true; + MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla; MozillaStyle.BreakConstructorInitializersBeforeComma = true; MozillaStyle.ConstructorInitializerIndentWidth = 2; MozillaStyle.ContinuationIndentWidth = 2; @@ -620,7 +627,9 @@ public: LessStashed(false), Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), Style(Style), IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), - Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false) { + Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), + MacroBlockBeginRegex(Style.MacroBlockBegin), + MacroBlockEndRegex(Style.MacroBlockEnd) { Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr, getFormattingLangOpts(Style))); Lex->SetKeepWhitespaceMode(true); @@ -1168,12 +1177,21 @@ private: Column = FormatTok->LastLineColumnWidth; } - if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() && - Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() == - tok::pp_define) && - std::find(ForEachMacros.begin(), ForEachMacros.end(), - FormatTok->Tok.getIdentifierInfo()) != ForEachMacros.end()) - FormatTok->Type = TT_ForEachMacro; + if (Style.Language == FormatStyle::LK_Cpp) { + if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() && + Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() == + tok::pp_define) && + std::find(ForEachMacros.begin(), ForEachMacros.end(), + FormatTok->Tok.getIdentifierInfo()) != ForEachMacros.end()) { + FormatTok->Type = TT_ForEachMacro; + } else if (FormatTok->is(tok::identifier)) { + if (MacroBlockBeginRegex.match(Text)) { + FormatTok->Type = TT_MacroBlockBegin; + } else if (MacroBlockEndRegex.match(Text)) { + FormatTok->Type = TT_MacroBlockEnd; + } + } + } return FormatTok; } @@ -1198,6 +1216,9 @@ private: bool FormattingDisabled; + llvm::Regex MacroBlockBeginRegex; + llvm::Regex MacroBlockEndRegex; + void readRawToken(FormatToken &Tok) { Lex->LexFromRawLexer(Tok.Tok); Tok.TokenText = StringRef(SourceMgr.getCharacterData(Tok.Tok.getLocation()), diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp index 316171dc1891..6c244c316604 100644 --- a/lib/Format/FormatToken.cpp +++ b/lib/Format/FormatToken.cpp @@ -23,6 +23,20 @@ namespace clang { namespace format { +const char *getTokenTypeName(TokenType Type) { + static const char *const TokNames[] = { +#define TYPE(X) #X, +LIST_TOKEN_TYPES +#undef TYPE + nullptr + }; + + if (Type < NUM_TOKEN_TYPES) + return TokNames[Type]; + llvm_unreachable("unknown TokenType"); + return nullptr; +} + // FIXME: This is copy&pasted from Sema. Put it in a common place and remove // duplication. bool FormatToken::isSimpleTypeSpecifier() const { diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 5b7dadb8545b..f335eda086c0 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -25,66 +25,77 @@ namespace clang { namespace format { +#define LIST_TOKEN_TYPES \ + TYPE(ArrayInitializerLSquare) \ + TYPE(ArraySubscriptLSquare) \ + TYPE(AttributeParen) \ + TYPE(BinaryOperator) \ + TYPE(BitFieldColon) \ + TYPE(BlockComment) \ + TYPE(CastRParen) \ + TYPE(ConditionalExpr) \ + TYPE(ConflictAlternative) \ + TYPE(ConflictEnd) \ + TYPE(ConflictStart) \ + TYPE(CtorInitializerColon) \ + TYPE(CtorInitializerComma) \ + TYPE(DesignatedInitializerPeriod) \ + TYPE(DictLiteral) \ + TYPE(ForEachMacro) \ + TYPE(FunctionAnnotationRParen) \ + TYPE(FunctionDeclarationName) \ + TYPE(FunctionLBrace) \ + TYPE(FunctionTypeLParen) \ + TYPE(ImplicitStringLiteral) \ + TYPE(InheritanceColon) \ + TYPE(InlineASMBrace) \ + TYPE(InlineASMColon) \ + TYPE(JavaAnnotation) \ + TYPE(JsComputedPropertyName) \ + TYPE(JsFatArrow) \ + TYPE(JsTypeColon) \ + TYPE(JsTypeOptionalQuestion) \ + TYPE(LambdaArrow) \ + TYPE(LambdaLSquare) \ + TYPE(LeadingJavaAnnotation) \ + TYPE(LineComment) \ + TYPE(MacroBlockBegin) \ + TYPE(MacroBlockEnd) \ + TYPE(ObjCBlockLBrace) \ + TYPE(ObjCBlockLParen) \ + TYPE(ObjCDecl) \ + TYPE(ObjCForIn) \ + TYPE(ObjCMethodExpr) \ + TYPE(ObjCMethodSpecifier) \ + TYPE(ObjCProperty) \ + TYPE(ObjCStringLiteral) \ + TYPE(OverloadedOperator) \ + TYPE(OverloadedOperatorLParen) \ + TYPE(PointerOrReference) \ + TYPE(PureVirtualSpecifier) \ + TYPE(RangeBasedForLoopColon) \ + TYPE(RegexLiteral) \ + TYPE(SelectorName) \ + TYPE(StartOfName) \ + TYPE(TemplateCloser) \ + TYPE(TemplateOpener) \ + TYPE(TemplateString) \ + TYPE(TrailingAnnotation) \ + TYPE(TrailingReturnArrow) \ + TYPE(TrailingUnaryOperator) \ + TYPE(UnaryOperator) \ + TYPE(Unknown) + enum TokenType { - TT_ArrayInitializerLSquare, - TT_ArraySubscriptLSquare, - TT_AttributeParen, - TT_BinaryOperator, - TT_BitFieldColon, - TT_BlockComment, - TT_CastRParen, - TT_ConditionalExpr, - TT_ConflictAlternative, - TT_ConflictEnd, - TT_ConflictStart, - TT_CtorInitializerColon, - TT_CtorInitializerComma, - TT_DesignatedInitializerPeriod, - TT_DictLiteral, - TT_ForEachMacro, - TT_FunctionAnnotationRParen, - TT_FunctionDeclarationName, - TT_FunctionLBrace, - TT_FunctionTypeLParen, - TT_ImplicitStringLiteral, - TT_InheritanceColon, - TT_InlineASMBrace, - TT_InlineASMColon, - TT_JavaAnnotation, - TT_JsComputedPropertyName, - TT_JsFatArrow, - TT_JsTypeColon, - TT_JsTypeOptionalQuestion, - TT_LambdaArrow, - TT_LambdaLSquare, - TT_LeadingJavaAnnotation, - TT_LineComment, - TT_ObjCBlockLBrace, - TT_ObjCBlockLParen, - TT_ObjCDecl, - TT_ObjCForIn, - TT_ObjCMethodExpr, - TT_ObjCMethodSpecifier, - TT_ObjCProperty, - TT_ObjCStringLiteral, - TT_OverloadedOperator, - TT_OverloadedOperatorLParen, - TT_PointerOrReference, - TT_PureVirtualSpecifier, - TT_RangeBasedForLoopColon, - TT_RegexLiteral, - TT_SelectorName, - TT_StartOfName, - TT_TemplateCloser, - TT_TemplateOpener, - TT_TemplateString, - TT_TrailingAnnotation, - TT_TrailingReturnArrow, - TT_TrailingUnaryOperator, - TT_UnaryOperator, - TT_Unknown +#define TYPE(X) TT_##X, +LIST_TOKEN_TYPES +#undef TYPE + NUM_TOKEN_TYPES }; +/// \brief Determines the name of a token type. +const char *getTokenTypeName(TokenType Type); + // Represents what type of block a set of braces open. enum BraceBlockKind { BK_Unknown, BK_Block, BK_BracedInit }; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 0e1f14ad05f2..ea8b30de8dfb 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -505,7 +505,8 @@ private: if (Line.MustBeDeclaration && Contexts.size() == 1 && !Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) && (!Tok->Previous || - !Tok->Previous->isOneOf(tok::kw_decltype, TT_LeadingJavaAnnotation))) + !Tok->Previous->isOneOf(tok::kw_decltype, tok::kw___attribute, + TT_LeadingJavaAnnotation))) Line.MightBeFunctionDecl = true; break; case tok::l_square: @@ -1627,6 +1628,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Right.is(Keywords.kw_function) && Left.isNot(tok::comma)) return 100; + if (Left.is(TT_JsTypeColon)) + return 100; } if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next && @@ -1705,7 +1708,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::l_paren) && InFunctionDecl && Style.AlignAfterOpenBracket) return 100; - if (Left.is(tok::l_paren) && Left.Previous && Left.Previous->is(tok::kw_if)) + if (Left.is(tok::l_paren) && Left.Previous && + Left.Previous->isOneOf(tok::kw_if, tok::kw_for)) return 1000; if (Left.is(tok::equal) && InFunctionDecl) return 110; @@ -2104,7 +2108,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return Right.HasUnescapedNewline; if (isAllmanBrace(Left) || isAllmanBrace(Right)) return Style.BreakBeforeBraces == FormatStyle::BS_Allman || - Style.BreakBeforeBraces == FormatStyle::BS_GNU; + Style.BreakBeforeBraces == FormatStyle::BS_GNU || + (Style.BreakBeforeBraces == FormatStyle::BS_Mozilla && + Line.startsWith(tok::kw_enum)); if (Style.Language == FormatStyle::LK_Proto && Left.isNot(tok::l_brace) && Right.is(TT_SelectorName)) return true; @@ -2205,6 +2211,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser)) return false; + if (Right.is(tok::r_square) && Right.MatchingParen && + Right.MatchingParen->is(TT_LambdaLSquare)) + return false; // We only break before r_brace if there was a corresponding break before // the l_brace, which is tracked by BreakBeforeClosingBrace. @@ -2265,7 +2274,8 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { const FormatToken *Tok = Line.First; while (Tok) { llvm::errs() << " M=" << Tok->MustBreakBefore - << " C=" << Tok->CanBreakBefore << " T=" << Tok->Type + << " C=" << Tok->CanBreakBefore + << " T=" << getTokenTypeName(Tok->Type) << " S=" << Tok->SpacesRequiredBefore << " B=" << Tok->BlockParameterCount << " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName() diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index c58e6bccd9bc..97fd98ecb947 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -269,7 +269,14 @@ void UnwrappedLineParser::parseFile() { void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { bool SwitchLabelEncountered = false; do { - switch (FormatTok->Tok.getKind()) { + tok::TokenKind kind = FormatTok->Tok.getKind(); + if (FormatTok->Type == TT_MacroBlockBegin) { + kind = tok::l_brace; + } else if (FormatTok->Type == TT_MacroBlockEnd) { + kind = tok::r_brace; + } + + switch (kind) { case tok::comment: nextToken(); addUnwrappedLine(); @@ -393,10 +400,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, bool MunchSemi) { - assert(FormatTok->Tok.is(tok::l_brace) && "'{' expected"); + assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && + "'{' or macro block token expected"); + const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin); + unsigned InitialLevel = Line->Level; nextToken(); + if (MacroBlock && FormatTok->is(tok::l_paren)) + parseParens(); + addUnwrappedLine(); ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, @@ -405,12 +418,17 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, ++Line->Level; parseLevel(/*HasOpeningBrace=*/true); - if (!FormatTok->Tok.is(tok::r_brace)) { + if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd) + : !FormatTok->is(tok::r_brace)) { Line->Level = InitialLevel; return; } nextToken(); // Munch the closing brace. + + if (MacroBlock && FormatTok->is(tok::l_paren)) + parseParens(); + if (MunchSemi && FormatTok->Tok.is(tok::semi)) nextToken(); Line->Level = InitialLevel; @@ -439,6 +457,8 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style, switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: return InitialToken.isOneOf(tok::kw_namespace, tok::kw_class); + case FormatStyle::BS_Mozilla: + return InitialToken.isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union); case FormatStyle::BS_Allman: case FormatStyle::BS_GNU: return true; @@ -757,6 +777,11 @@ void UnwrappedLineParser::parseStructuralElement() { parseForOrWhileLoop(); return; } + if (FormatTok->is(TT_MacroBlockBegin)) { + parseBlock(/*MustBeDeclaration=*/false, /*AddLevel=*/true, + /*MunchSemi=*/false); + return; + } if (Style.Language == FormatStyle::LK_JavaScript && FormatTok->is(Keywords.kw_import)) { parseJavaScriptEs6ImportExport(); @@ -860,6 +885,11 @@ void UnwrappedLineParser::parseStructuralElement() { parseTryCatch(); return; case tok::identifier: { + if (FormatTok->is(TT_MacroBlockEnd)) { + addUnwrappedLine(); + return; + } + // Parse function literal unless 'function' is the first token in a line // in which case this should be treated as a free-standing function. if (Style.Language == FormatStyle::LK_JavaScript && @@ -872,7 +902,7 @@ void UnwrappedLineParser::parseStructuralElement() { FormatTok->is(Keywords.kw_interface)) { parseRecord(); addUnwrappedLine(); - break; + return; } StringRef Text = FormatTok->TokenText; diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 01c56bdc4df9..57c97d0c312f 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -353,6 +353,7 @@ void ASTUnit::CacheCodeCompletionResults() { // Translate global code completions into cached completions. llvm::DenseMap<CanQualType, unsigned> CompletionTypes; + CodeCompletionContext CCContext(CodeCompletionContext::CCC_TopLevel); for (Result &R : Results) { switch (R.Kind) { @@ -360,7 +361,7 @@ void ASTUnit::CacheCodeCompletionResults() { bool IsNestedNameSpecifier = false; CachedCodeCompletionResult CachedResult; CachedResult.Completion = R.CreateCodeCompletionString( - *TheSema, *CachedCompletionAllocator, CCTUInfo, + *TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = getDeclShowContexts( R.Declaration, Ctx->getLangOpts(), IsNestedNameSpecifier); @@ -423,7 +424,7 @@ void ASTUnit::CacheCodeCompletionResults() { // nested-name-specifier completion. R.StartsNestedNameSpecifier = true; CachedResult.Completion = R.CreateCodeCompletionString( - *TheSema, *CachedCompletionAllocator, CCTUInfo, + *TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = RemainingContexts; CachedResult.Priority = CCP_NestedNameSpecifier; @@ -444,7 +445,7 @@ void ASTUnit::CacheCodeCompletionResults() { case Result::RK_Macro: { CachedCodeCompletionResult CachedResult; CachedResult.Completion = R.CreateCodeCompletionString( - *TheSema, *CachedCompletionAllocator, CCTUInfo, + *TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = (1LL << CodeCompletionContext::CCC_TopLevel) diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 6b0fed676182..ff041a8ec431 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -405,7 +405,7 @@ void CompilerInstance::createPCHExternalASTSource( } IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( - StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, + StringRef Path, StringRef Sysroot, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, const PCHContainerOperations &PCHContainerOps, void *DeserializationListener, bool OwnDeserializationListener, @@ -413,7 +413,7 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource( HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); IntrusiveRefCntPtr<ASTReader> Reader(new ASTReader( - PP, Context, PCHContainerOps, Sysroot.empty() ? "" : Sysroot.c_str(), + PP, Context, PCHContainerOps, Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation, AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false, HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex)); @@ -497,12 +497,14 @@ void CompilerInstance::createCodeCompletionConsumer() { } void CompilerInstance::createFrontendTimer() { - FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); + FrontendTimerGroup.reset(new llvm::TimerGroup("Clang front-end time report")); + FrontendTimer.reset( + new llvm::Timer("Clang front-end timer", *FrontendTimerGroup)); } CodeCompleteConsumer * CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, - const std::string &Filename, + StringRef Filename, unsigned Line, unsigned Column, const CodeCompleteOptions &Opts, @@ -1237,13 +1239,18 @@ void CompilerInstance::createModuleManager() { HeaderSearchOptions &HSOpts = getHeaderSearchOpts(); std::string Sysroot = HSOpts.Sysroot; const PreprocessorOptions &PPOpts = getPreprocessorOpts(); + std::unique_ptr<llvm::Timer> ReadTimer; + if (FrontendTimerGroup) + ReadTimer = llvm::make_unique<llvm::Timer>("Reading modules", + *FrontendTimerGroup); ModuleManager = new ASTReader( getPreprocessor(), *Context, *getPCHContainerOperations(), Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation, /*AllowASTWithCompilerErrors=*/false, /*AllowConfigurationMismatch=*/false, HSOpts.ModulesValidateSystemHeaders, - getFrontendOpts().UseGlobalModuleIndex); + getFrontendOpts().UseGlobalModuleIndex, + std::move(ReadTimer)); if (hasASTConsumer()) { ModuleManager->setDeserializationListener( getASTConsumer().GetASTDeserializationListener()); @@ -1259,6 +1266,11 @@ void CompilerInstance::createModuleManager() { } bool CompilerInstance::loadModuleFile(StringRef FileName) { + llvm::Timer Timer; + if (FrontendTimerGroup) + Timer.init("Preloading " + FileName.str(), *FrontendTimerGroup); + llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); + // Helper to recursively read the module names for all modules we're adding. // We mark these as known and redirect any attempt to load that module to // the files we were handed. @@ -1418,6 +1430,11 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, for (auto &Listener : DependencyCollectors) Listener->attachToASTReader(*ModuleManager); + llvm::Timer Timer; + if (FrontendTimerGroup) + Timer.init("Loading " + ModuleFileName, *FrontendTimerGroup); + llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); + // Try to load the module file. unsigned ARRFlags = Explicit ? 0 : ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index dd664ca652f0..6f13faf573be 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -508,6 +508,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.MergeFunctions = Args.hasArg(OPT_fmerge_functions); + Opts.PrepareForLTO = Args.hasArg(OPT_flto); + Opts.MSVolatile = Args.hasArg(OPT_fms_volatile); Opts.VectorizeBB = Args.hasArg(OPT_vectorize_slp_aggressive); @@ -555,6 +557,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_fsanitize_coverage_8bit_counters); Opts.SanitizeMemoryTrackOrigins = getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); + Opts.SanitizeMemoryUseAfterDtor = + Args.hasArg(OPT_fsanitize_memory_use_after_dtor); Opts.SSPBufferSize = getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); @@ -1647,6 +1651,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Check if -fopenmp is specified. Opts.OpenMP = Args.hasArg(options::OPT_fopenmp); + Opts.OpenMPUseTLS = + Opts.OpenMP && !Args.hasArg(options::OPT_fnoopenmp_use_tls); // Record whether the __DEPRECATED define was requested. Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro, diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp index 4a8a8a029e79..2afd23fcb9e8 100644 --- a/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" +#include "clang/Driver/Action.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" @@ -61,9 +62,25 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, } // We expect to get back exactly one command job, if we didn't something - // failed. + // failed. CUDA compilation is an exception as it creates multiple jobs. If + // that's the case, we proceed with the first job. If caller needs particular + // CUDA job, it should be controlled via --cuda-{host|device}-only option + // passed to the driver. const driver::JobList &Jobs = C->getJobs(); - if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { + bool CudaCompilation = false; + if (Jobs.size() > 1) { + for (auto &A : C->getActions()){ + // On MacOSX real actions may end up being wrapped in BindArchAction + if (isa<driver::BindArchAction>(A)) + A = *A->begin(); + if (isa<driver::CudaDeviceAction>(A)) { + CudaCompilation = true; + break; + } + } + } + if (Jobs.size() == 0 || !isa<driver::Command>(*Jobs.begin()) || + (Jobs.size() > 1 && !CudaCompilation)) { SmallString<256> Msg; llvm::raw_svector_ostream OS(Msg); Jobs.Print(OS, "; ", true); diff --git a/lib/Frontend/PCHContainerOperations.cpp b/lib/Frontend/PCHContainerOperations.cpp index fd3278b3b145..c749bb5c8db4 100644 --- a/lib/Frontend/PCHContainerOperations.cpp +++ b/lib/Frontend/PCHContainerOperations.cpp @@ -18,8 +18,6 @@ #include "clang/Lex/ModuleLoader.h" using namespace clang; -PCHContainerOperations::~PCHContainerOperations() {} - namespace { /// \brief A PCHContainerGenerator that writes out the PCH to a flat file. diff --git a/lib/Headers/Intrin.h b/lib/Headers/Intrin.h index 7ba311ea4b94..24b3eae8bf86 100644 --- a/lib/Headers/Intrin.h +++ b/lib/Headers/Intrin.h @@ -513,47 +513,40 @@ _BitScanReverse(unsigned long *_Index, unsigned long _Mask) { return 1; } static __inline__ unsigned short __DEFAULT_FN_ATTRS -__popcnt16(unsigned short value) { - return __builtin_popcount((int)value); +__popcnt16(unsigned short _Value) { + return __builtin_popcount((int)_Value); } static __inline__ unsigned int __DEFAULT_FN_ATTRS -__popcnt(unsigned int value) { - return __builtin_popcount(value); +__popcnt(unsigned int _Value) { + return __builtin_popcount(_Value); } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittest(long const *a, long b) { - return (*a >> b) & 1; +_bittest(long const *_BitBase, long _BitPos) { + return (*_BitBase >> _BitPos) & 1; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandcomplement(long *a, long b) { - unsigned char x = (*a >> b) & 1; - *a = *a ^ (1 << b); - return x; +_bittestandcomplement(long *_BitBase, long _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase ^ (1 << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandreset(long *a, long b) { - unsigned char x = (*a >> b) & 1; - *a = *a & ~(1 << b); - return x; +_bittestandreset(long *_BitBase, long _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase & ~(1 << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandset(long *a, long b) { - unsigned char x = (*a >> b) & 1; - *a = *a | (1 << b); - return x; +_bittestandset(long *_BitBase, long _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase | (1 << _BitPos); + return _Res; } -#if defined(__i386__) || defined(__x86_64__) static __inline__ unsigned char __DEFAULT_FN_ATTRS -_interlockedbittestandset(long volatile *__BitBase, long __BitPos) { - unsigned char __Res; - __asm__ ("xor %0, %0\n" - "lock bts %2, %1\n" - "setc %0\n" - : "=r" (__Res), "+m"(*__BitBase) - : "Ir"(__BitPos)); - return __Res; +_interlockedbittestandset(long volatile *_BitBase, long _BitPos) { + long _PrevVal = __atomic_fetch_or(_BitBase, 1l << _BitPos, __ATOMIC_SEQ_CST); + return (_PrevVal >> _BitPos) & 1; } -#endif #ifdef __x86_64__ static __inline__ unsigned char __DEFAULT_FN_ATTRS _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask) { @@ -571,40 +564,36 @@ _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask) { } static __inline__ unsigned __int64 __DEFAULT_FN_ATTRS - __popcnt64(unsigned __int64 value) { - return __builtin_popcountll(value); +__popcnt64(unsigned __int64 _Value) { + return __builtin_popcountll(_Value); } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittest64(__int64 const *a, __int64 b) { - return (*a >> b) & 1; +_bittest64(__int64 const *_BitBase, __int64 _BitPos) { + return (*_BitBase >> _BitPos) & 1; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandcomplement64(__int64 *a, __int64 b) { - unsigned char x = (*a >> b) & 1; - *a = *a ^ (1ll << b); - return x; +_bittestandcomplement64(__int64 *_BitBase, __int64 _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase ^ (1ll << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandreset64(__int64 *a, __int64 b) { - unsigned char x = (*a >> b) & 1; - *a = *a & ~(1ll << b); - return x; +_bittestandreset64(__int64 *_BitBase, __int64 _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase & ~(1ll << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_bittestandset64(__int64 *a, __int64 b) { - unsigned char x = (*a >> b) & 1; - *a = *a | (1ll << b); - return x; +_bittestandset64(__int64 *_BitBase, __int64 _BitPos) { + unsigned char _Res = (*_BitBase >> _BitPos) & 1; + *_BitBase = *_BitBase | (1ll << _BitPos); + return _Res; } static __inline__ unsigned char __DEFAULT_FN_ATTRS -_interlockedbittestandset64(__int64 volatile *__BitBase, __int64 __BitPos) { - unsigned char __Res; - __asm__ ("xor %0, %0\n" - "lock bts %2, %1\n" - "setc %0\n" - : "=r" (__Res), "+m"(*__BitBase) - : "Ir"(__BitPos)); - return __Res; +_interlockedbittestandset64(__int64 volatile *_BitBase, __int64 _BitPos) { + long long _PrevVal = + __atomic_fetch_or(_BitBase, 1ll << _BitPos, __ATOMIC_SEQ_CST); + return (_PrevVal >> _BitPos) & 1; } #endif /*----------------------------------------------------------------------------*\ @@ -612,16 +601,16 @@ _interlockedbittestandset64(__int64 volatile *__BitBase, __int64 __BitPos) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedExchangeAdd8(char volatile *_Addend, char _Value) { - return __atomic_add_fetch(_Addend, _Value, 0) - _Value; + return __atomic_fetch_add(_Addend, _Value, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedExchangeAdd16(short volatile *_Addend, short _Value) { - return __atomic_add_fetch(_Addend, _Value, 0) - _Value; + return __atomic_fetch_add(_Addend, _Value, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchangeAdd64(__int64 volatile *_Addend, __int64 _Value) { - return __atomic_add_fetch(_Addend, _Value, 0) - _Value; + return __atomic_fetch_add(_Addend, _Value, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -629,20 +618,20 @@ _InterlockedExchangeAdd64(__int64 volatile *_Addend, __int64 _Value) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedExchangeSub8(char volatile *_Subend, char _Value) { - return __atomic_sub_fetch(_Subend, _Value, 0) + _Value; + return __atomic_fetch_sub(_Subend, _Value, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedExchangeSub16(short volatile *_Subend, short _Value) { - return __atomic_sub_fetch(_Subend, _Value, 0) + _Value; + return __atomic_fetch_sub(_Subend, _Value, __ATOMIC_SEQ_CST); } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedExchangeSub(long volatile *_Subend, long _Value) { - return __atomic_sub_fetch(_Subend, _Value, 0) + _Value; + return __atomic_fetch_sub(_Subend, _Value, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchangeSub64(__int64 volatile *_Subend, __int64 _Value) { - return __atomic_sub_fetch(_Subend, _Value, 0) + _Value; + return __atomic_fetch_sub(_Subend, _Value, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -650,12 +639,12 @@ _InterlockedExchangeSub64(__int64 volatile *_Subend, __int64 _Value) { \*----------------------------------------------------------------------------*/ static __inline__ short __DEFAULT_FN_ATTRS _InterlockedIncrement16(short volatile *_Value) { - return __atomic_add_fetch(_Value, 1, 0); + return __atomic_add_fetch(_Value, 1, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedIncrement64(__int64 volatile *_Value) { - return __atomic_add_fetch(_Value, 1, 0); + return __atomic_add_fetch(_Value, 1, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -663,12 +652,12 @@ _InterlockedIncrement64(__int64 volatile *_Value) { \*----------------------------------------------------------------------------*/ static __inline__ short __DEFAULT_FN_ATTRS _InterlockedDecrement16(short volatile *_Value) { - return __atomic_sub_fetch(_Value, 1, 0); + return __atomic_sub_fetch(_Value, 1, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedDecrement64(__int64 volatile *_Value) { - return __atomic_sub_fetch(_Value, 1, 0); + return __atomic_sub_fetch(_Value, 1, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -676,20 +665,20 @@ _InterlockedDecrement64(__int64 volatile *_Value) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedAnd8(char volatile *_Value, char _Mask) { - return __atomic_and_fetch(_Value, _Mask, 0); + return __atomic_and_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedAnd16(short volatile *_Value, short _Mask) { - return __atomic_and_fetch(_Value, _Mask, 0); + return __atomic_and_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedAnd(long volatile *_Value, long _Mask) { - return __atomic_and_fetch(_Value, _Mask, 0); + return __atomic_and_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedAnd64(__int64 volatile *_Value, __int64 _Mask) { - return __atomic_and_fetch(_Value, _Mask, 0); + return __atomic_and_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -697,20 +686,20 @@ _InterlockedAnd64(__int64 volatile *_Value, __int64 _Mask) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedOr8(char volatile *_Value, char _Mask) { - return __atomic_or_fetch(_Value, _Mask, 0); + return __atomic_or_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedOr16(short volatile *_Value, short _Mask) { - return __atomic_or_fetch(_Value, _Mask, 0); + return __atomic_or_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedOr(long volatile *_Value, long _Mask) { - return __atomic_or_fetch(_Value, _Mask, 0); + return __atomic_or_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedOr64(__int64 volatile *_Value, __int64 _Mask) { - return __atomic_or_fetch(_Value, _Mask, 0); + return __atomic_or_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -718,20 +707,20 @@ _InterlockedOr64(__int64 volatile *_Value, __int64 _Mask) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedXor8(char volatile *_Value, char _Mask) { - return __atomic_xor_fetch(_Value, _Mask, 0); + return __atomic_xor_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedXor16(short volatile *_Value, short _Mask) { - return __atomic_xor_fetch(_Value, _Mask, 0); + return __atomic_xor_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedXor(long volatile *_Value, long _Mask) { - return __atomic_xor_fetch(_Value, _Mask, 0); + return __atomic_xor_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedXor64(__int64 volatile *_Value, __int64 _Mask) { - return __atomic_xor_fetch(_Value, _Mask, 0); + return __atomic_xor_fetch(_Value, _Mask, __ATOMIC_SEQ_CST); } #endif /*----------------------------------------------------------------------------*\ @@ -739,18 +728,18 @@ _InterlockedXor64(__int64 volatile *_Value, __int64 _Mask) { \*----------------------------------------------------------------------------*/ static __inline__ char __DEFAULT_FN_ATTRS _InterlockedExchange8(char volatile *_Target, char _Value) { - __atomic_exchange(_Target, &_Value, &_Value, 0); + __atomic_exchange(_Target, &_Value, &_Value, __ATOMIC_SEQ_CST); return _Value; } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedExchange16(short volatile *_Target, short _Value) { - __atomic_exchange(_Target, &_Value, &_Value, 0); + __atomic_exchange(_Target, &_Value, &_Value, __ATOMIC_SEQ_CST); return _Value; } #ifdef __x86_64__ static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchange64(__int64 volatile *_Target, __int64 _Value) { - __atomic_exchange(_Target, &_Value, &_Value, 0); + __atomic_exchange(_Target, &_Value, &_Value, __ATOMIC_SEQ_CST); return _Value; } #endif @@ -760,19 +749,22 @@ _InterlockedExchange64(__int64 volatile *_Target, __int64 _Value) { static __inline__ char __DEFAULT_FN_ATTRS _InterlockedCompareExchange8(char volatile *_Destination, char _Exchange, char _Comparand) { - __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0); + __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _Comparand; } static __inline__ short __DEFAULT_FN_ATTRS _InterlockedCompareExchange16(short volatile *_Destination, short _Exchange, short _Comparand) { - __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0); + __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _Comparand; } static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedCompareExchange64(__int64 volatile *_Destination, __int64 _Exchange, __int64 _Comparand) { - __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0); + __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _Comparand; } /*----------------------------------------------------------------------------*\ diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h index 2c80e24db335..f52bcbc5b4a8 100644 --- a/lib/Headers/altivec.h +++ b/lib/Headers/altivec.h @@ -48,7 +48,8 @@ static vector bool char __ATTRS_o_ai vec_perm(vector bool char __a, vector bool char __b, vector unsigned char __c); -static vector short __ATTRS_o_ai vec_perm(vector short __a, vector short __b, +static vector short __ATTRS_o_ai vec_perm(vector signed short __a, + vector signed short __b, vector unsigned char __c); static vector unsigned short __ATTRS_o_ai vec_perm(vector unsigned short __a, @@ -62,7 +63,8 @@ static vector bool short __ATTRS_o_ai vec_perm(vector bool short __a, static vector pixel __ATTRS_o_ai vec_perm(vector pixel __a, vector pixel __b, vector unsigned char __c); -static vector int __ATTRS_o_ai vec_perm(vector int __a, vector int __b, +static vector int __ATTRS_o_ai vec_perm(vector signed int __a, + vector signed int __b, vector unsigned char __c); static vector unsigned int __ATTRS_o_ai vec_perm(vector unsigned int __a, @@ -77,14 +79,18 @@ static vector float __ATTRS_o_ai vec_perm(vector float __a, vector float __b, vector unsigned char __c); #ifdef __VSX__ -static vector long long __ATTRS_o_ai vec_perm(vector long long __a, - vector long long __b, +static vector long long __ATTRS_o_ai vec_perm(vector signed long long __a, + vector signed long long __b, vector unsigned char __c); static vector unsigned long long __ATTRS_o_ai vec_perm(vector unsigned long long __a, vector unsigned long long __b, vector unsigned char __c); +static vector bool long long __ATTRS_o_ai +vec_perm(vector bool long long __a, vector bool long long __b, + vector unsigned char __c); + static vector double __ATTRS_o_ai vec_perm(vector double __a, vector double __b, vector unsigned char __c); #endif @@ -1735,6 +1741,48 @@ static vector bool long long __ATTRS_o_ai vec_cmplt(vector unsigned long long __a, vector unsigned long long __b) { return vec_cmpgt(__b, __a); } + +/* vec_cntlz */ + +static vector signed char __ATTRS_o_ai vec_cntlz(vector signed char __a) { + return __builtin_altivec_vclzb(__a); +} +static vector unsigned char __ATTRS_o_ai vec_cntlz(vector unsigned char __a) { + return __builtin_altivec_vclzb(__a); +} +static vector signed short __ATTRS_o_ai vec_cntlz(vector signed short __a) { + return __builtin_altivec_vclzh(__a); +} +static vector unsigned short __ATTRS_o_ai vec_cntlz(vector unsigned short __a) { + return __builtin_altivec_vclzh(__a); +} +static vector signed int __ATTRS_o_ai vec_cntlz(vector signed int __a) { + return __builtin_altivec_vclzw(__a); +} +static vector unsigned int __ATTRS_o_ai vec_cntlz(vector unsigned int __a) { + return __builtin_altivec_vclzw(__a); +} +static vector signed long long __ATTRS_o_ai +vec_cntlz(vector signed long long __a) { + return __builtin_altivec_vclzd(__a); +} +static vector unsigned long long __ATTRS_o_ai +vec_cntlz(vector unsigned long long __a) { + return __builtin_altivec_vclzd(__a); +} +#endif + +/* vec_cpsgn */ + +#ifdef __VSX__ +static vector float __ATTRS_o_ai vec_cpsgn(vector float __a, vector float __b) { + return __builtin_vsx_xvcpsgnsp(__a, __b); +} + +static vector double __ATTRS_o_ai vec_cpsgn(vector double __a, + vector double __b) { + return __builtin_vsx_xvcpsgndp(__a, __b); +} #endif /* vec_ctf */ @@ -1790,14 +1838,58 @@ vec_vctuxs(vector float __a, int __b) { } /* vec_div */ + +/* Integer vector divides (vectors are scalarized, elements divided + and the vectors reassembled). +*/ +static vector signed char __ATTRS_o_ai vec_div(vector signed char __a, + vector signed char __b) { + return __a / __b; +} + +static vector unsigned char __ATTRS_o_ai vec_div(vector unsigned char __a, + vector unsigned char __b) { + return __a / __b; +} + +static vector signed short __ATTRS_o_ai vec_div(vector signed short __a, + vector signed short __b) { + return __a / __b; +} + +static vector unsigned short __ATTRS_o_ai vec_div(vector unsigned short __a, + vector unsigned short __b) { + return __a / __b; +} + +static vector signed int __ATTRS_o_ai vec_div(vector signed int __a, + vector signed int __b) { + return __a / __b; +} + +static vector unsigned int __ATTRS_o_ai vec_div(vector unsigned int __a, + vector unsigned int __b) { + return __a / __b; +} + #ifdef __VSX__ +static vector signed long long __ATTRS_o_ai +vec_div(vector signed long long __a, vector signed long long __b) { + return __a / __b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_div(vector unsigned long long __a, vector unsigned long long __b) { + return __a / __b; +} + static vector float __ATTRS_o_ai vec_div(vector float __a, vector float __b) { - return __builtin_vsx_xvdivsp(__a, __b); + return __a / __b; } static vector double __ATTRS_o_ai vec_div(vector double __a, vector double __b) { - return __builtin_vsx_xvdivdp(__a, __b); + return __a / __b; } #endif @@ -1841,6 +1933,189 @@ vec_dstt(const void *__a, int __b, int __c) { __builtin_altivec_dstt(__a, __b, __c); } +/* vec_eqv */ + +#ifdef __POWER8_VECTOR__ +static vector signed char __ATTRS_o_ai vec_eqv(vector signed char __a, + vector signed char __b) { + return (vector signed char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed char __ATTRS_o_ai vec_eqv(vector bool char __a, + vector signed char __b) { + return (vector signed char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed char __ATTRS_o_ai vec_eqv(vector signed char __a, + vector bool char __b) { + return (vector signed char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned char __ATTRS_o_ai vec_eqv(vector unsigned char __a, + vector unsigned char __b) { + return (vector unsigned char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned char __ATTRS_o_ai vec_eqv(vector bool char __a, + vector unsigned char __b) { + return (vector unsigned char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned char __ATTRS_o_ai vec_eqv(vector unsigned char __a, + vector bool char __b) { + return (vector unsigned char)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed short __ATTRS_o_ai vec_eqv(vector signed short __a, + vector signed short __b) { + return (vector signed short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed short __ATTRS_o_ai vec_eqv(vector bool short __a, + vector signed short __b) { + return (vector signed short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed short __ATTRS_o_ai vec_eqv(vector signed short __a, + vector bool short __b) { + return (vector signed short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned short __ATTRS_o_ai vec_eqv(vector unsigned short __a, + vector unsigned short __b) { + return (vector unsigned short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned short __ATTRS_o_ai vec_eqv(vector bool short __a, + vector unsigned short __b) { + return (vector unsigned short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned short __ATTRS_o_ai vec_eqv(vector unsigned short __a, + vector bool short __b) { + return (vector unsigned short)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed int __ATTRS_o_ai vec_eqv(vector signed int __a, + vector signed int __b) { + return (vector signed int)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed int __ATTRS_o_ai vec_eqv(vector bool int __a, + vector signed int __b) { + return (vector signed int)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed int __ATTRS_o_ai vec_eqv(vector signed int __a, + vector bool int __b) { + return (vector signed int)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned int __ATTRS_o_ai vec_eqv(vector unsigned int __a, + vector unsigned int __b) { + return __builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned int __ATTRS_o_ai vec_eqv(vector bool int __a, + vector unsigned int __b) { + return __builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector unsigned int __ATTRS_o_ai vec_eqv(vector unsigned int __a, + vector bool int __b) { + return __builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector signed long long __ATTRS_o_ai +vec_eqv(vector signed long long __a, vector signed long long __b) { + return (vector signed long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector signed long long __ATTRS_o_ai +vec_eqv(vector bool long long __a, vector signed long long __b) { + return (vector signed long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector signed long long __ATTRS_o_ai +vec_eqv(vector signed long long __a, vector bool long long __b) { + return (vector signed long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_eqv(vector unsigned long long __a, vector unsigned long long __b) { + return (vector unsigned long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_eqv(vector bool long long __a, vector unsigned long long __b) { + return (vector unsigned long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_eqv(vector unsigned long long __a, vector bool long long __b) { + return (vector unsigned long long) + __builtin_vsx_xxleqv((vector unsigned int)__a, (vector unsigned int)__b); +} + +static vector float __ATTRS_o_ai vec_eqv(vector float __a, vector float __b) { + return (vector float)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector float __ATTRS_o_ai vec_eqv(vector bool int __a, + vector float __b) { + return (vector float)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector float __ATTRS_o_ai vec_eqv(vector float __a, + vector bool int __b) { + return (vector float)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector double __ATTRS_o_ai vec_eqv(vector double __a, + vector double __b) { + return (vector double)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector double __ATTRS_o_ai vec_eqv(vector bool long long __a, + vector double __b) { + return (vector double)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} + +static vector double __ATTRS_o_ai vec_eqv(vector double __a, + vector bool long long __b) { + return (vector double)__builtin_vsx_xxleqv((vector unsigned int)__a, + (vector unsigned int)__b); +} +#endif + /* vec_expte */ static vector float __attribute__((__always_inline__)) @@ -1857,10 +2132,19 @@ vec_vexptefp(vector float __a) { /* vec_floor */ -static vector float __attribute__((__always_inline__)) -vec_floor(vector float __a) { +static vector float __ATTRS_o_ai vec_floor(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvrspim(__a); +#else return __builtin_altivec_vrfim(__a); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_floor(vector double __a) { + return __builtin_vsx_xvrdpim(__a); } +#endif /* vec_vrfim */ @@ -2532,10 +2816,21 @@ static vector unsigned char __ATTRS_o_ai vec_lvsr(int __a, const float *__b) { /* vec_madd */ -static vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_madd(vector float __a, vector float __b, vector float __c) { +#ifdef __VSX__ + return __builtin_vsx_xvmaddasp(__a, __b, __c); +#else return __builtin_altivec_vmaddfp(__a, __b, __c); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_madd(vector double __a, vector double __b, vector double __c) { + return __builtin_vsx_xvmaddadp(__a, __b, __c); } +#endif /* vec_vmaddfp */ @@ -2559,6 +2854,20 @@ vec_vmhaddshs(vector signed short __a, vector signed short __b, return __builtin_altivec_vmhaddshs(__a, __b, __c); } +/* vec_msub */ + +#ifdef __VSX__ +static vector float __ATTRS_o_ai +vec_msub(vector float __a, vector float __b, vector float __c) { + return __builtin_vsx_xvmsubasp(__a, __b, __c); +} + +static vector double __ATTRS_o_ai +vec_msub(vector double __a, vector double __b, vector double __c) { + return __builtin_vsx_xvmsubadp(__a, __b, __c); +} +#endif + /* vec_max */ static vector signed char __ATTRS_o_ai vec_max(vector signed char __a, @@ -2893,6 +3202,86 @@ static vector float __ATTRS_o_ai vec_mergeh(vector float __a, 0x14, 0x15, 0x16, 0x17)); } +#ifdef __VSX__ +static vector signed long long __ATTRS_o_ai +vec_mergeh(vector signed long long __a, vector signed long long __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector signed long long __ATTRS_o_ai +vec_mergeh(vector signed long long __a, vector bool long long __b) { + return vec_perm(__a, (vector signed long long)__b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector signed long long __ATTRS_o_ai +vec_mergeh(vector bool long long __a, vector signed long long __b) { + return vec_perm((vector signed long long)__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector unsigned long long __ATTRS_o_ai +vec_mergeh(vector unsigned long long __a, vector unsigned long long __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector unsigned long long __ATTRS_o_ai +vec_mergeh(vector unsigned long long __a, vector bool long long __b) { + return vec_perm(__a, (vector unsigned long long)__b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} + +static vector unsigned long long __ATTRS_o_ai +vec_mergeh(vector bool long long __a, vector unsigned long long __b) { + return vec_perm((vector unsigned long long)__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} +static vector double __ATTRS_o_ai vec_mergeh(vector double __a, + vector double __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} +static vector double __ATTRS_o_ai vec_mergeh(vector double __a, + vector bool long long __b) { + return vec_perm(__a, (vector double)__b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} +static vector double __ATTRS_o_ai vec_mergeh(vector bool long long __a, + vector double __b) { + return vec_perm((vector double)__a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17)); +} +#endif + /* vec_vmrghb */ #define __builtin_altivec_vmrghb vec_vmrghb @@ -3081,6 +3470,81 @@ static vector float __ATTRS_o_ai vec_mergel(vector float __a, 0x1C, 0x1D, 0x1E, 0x1F)); } +#ifdef __VSX__ +static vector signed long long __ATTRS_o_ai +vec_mergel(vector signed long long __a, vector signed long long __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector signed long long __ATTRS_o_ai +vec_mergel(vector signed long long __a, vector bool long long __b) { + return vec_perm(__a, (vector signed long long)__b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector signed long long __ATTRS_o_ai +vec_mergel(vector bool long long __a, vector signed long long __b) { + return vec_perm((vector signed long long)__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector unsigned long long __ATTRS_o_ai +vec_mergel(vector unsigned long long __a, vector unsigned long long __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector unsigned long long __ATTRS_o_ai +vec_mergel(vector unsigned long long __a, vector bool long long __b) { + return vec_perm(__a, (vector unsigned long long)__b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector unsigned long long __ATTRS_o_ai +vec_mergel(vector bool long long __a, vector unsigned long long __b) { + return vec_perm((vector unsigned long long)__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector double __ATTRS_o_ai +vec_mergel(vector double __a, vector double __b) { + return vec_perm(__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector double __ATTRS_o_ai +vec_mergel(vector double __a, vector bool long long __b) { + return vec_perm(__a, (vector double)__b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +static vector double __ATTRS_o_ai +vec_mergel(vector bool long long __a, vector double __b) { + return vec_perm((vector double)__a, __b, + (vector unsigned char)(0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x18, 0X19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F)); +} +#endif + /* vec_vmrglb */ #define __builtin_altivec_vmrglb vec_vmrglb @@ -3677,6 +4141,65 @@ static void __ATTRS_o_ai vec_mtvscr(vector float __a) { __builtin_altivec_mtvscr((vector int)__a); } +/* vec_mul */ + +/* Integer vector multiplication will involve multiplication of the odd/even + elements separately, then truncating the results and moving to the + result vector. +*/ +static vector signed char __ATTRS_o_ai vec_mul(vector signed char __a, + vector signed char __b) { + return __a * __b; +} + +static vector unsigned char __ATTRS_o_ai vec_mul(vector unsigned char __a, + vector unsigned char __b) { + return __a * __b; +} + +static vector signed short __ATTRS_o_ai vec_mul(vector signed short __a, + vector signed short __b) { + return __a * __b; +} + +static vector unsigned short __ATTRS_o_ai vec_mul(vector unsigned short __a, + vector unsigned short __b) { + return __a * __b; +} + +static vector signed int __ATTRS_o_ai vec_mul(vector signed int __a, + vector signed int __b) { + return __a * __b; +} + +static vector unsigned int __ATTRS_o_ai vec_mul(vector unsigned int __a, + vector unsigned int __b) { + return __a * __b; +} + +#ifdef __VSX__ +static vector signed long long __ATTRS_o_ai +vec_mul(vector signed long long __a, vector signed long long __b) { + return __a * __b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_mul(vector unsigned long long __a, vector unsigned long long __b) { + return __a * __b; +} +#endif + +static vector float __ATTRS_o_ai vec_mul(vector float __a, vector float __b) { + return __a * __b; +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_mul(vector double __a, vector double __b) { + return __a * __b; +} +#endif + /* The vmulos* and vmules* instructions have a big endian bias, so we must reverse the meaning of "even" and "odd" for little endian. */ @@ -3882,12 +4405,165 @@ vec_vmulouh(vector unsigned short __a, vector unsigned short __b) { #endif } +/* vec_nand */ + +#ifdef __POWER8_VECTOR__ +static vector signed char __ATTRS_o_ai vec_nand(vector signed char __a, + vector signed char __b) { + return ~(__a & __b); +} + +static vector signed char __ATTRS_o_ai vec_nand(vector signed char __a, + vector bool char __b) { + return ~(__a & __b); +} + +static vector signed char __ATTRS_o_ai vec_nand(vector bool char __a, + vector signed char __b) { + return ~(__a & __b); +} + +static vector unsigned char __ATTRS_o_ai vec_nand(vector unsigned char __a, + vector unsigned char __b) { + return ~(__a & __b); +} + +static vector unsigned char __ATTRS_o_ai vec_nand(vector unsigned char __a, + vector bool char __b) { + return ~(__a & __b); + +} + +static vector unsigned char __ATTRS_o_ai vec_nand(vector bool char __a, + vector unsigned char __b) { + return ~(__a & __b); +} + +static vector signed short __ATTRS_o_ai vec_nand(vector signed short __a, + vector signed short __b) { + return ~(__a & __b); +} + +static vector signed short __ATTRS_o_ai vec_nand(vector signed short __a, + vector bool short __b) { + return ~(__a & __b); +} + +static vector signed short __ATTRS_o_ai vec_nand(vector bool short __a, + vector signed short __b) { + return ~(__a & __b); +} + +static vector unsigned short __ATTRS_o_ai vec_nand(vector unsigned short __a, + vector unsigned short __b) { + return ~(__a & __b); +} + +static vector unsigned short __ATTRS_o_ai vec_nand(vector unsigned short __a, + vector bool short __b) { + return ~(__a & __b); + +} + +static vector unsigned short __ATTRS_o_ai vec_nand(vector bool short __a, + vector unsigned short __b) { + return ~(__a & __b); + +} + +static vector signed int __ATTRS_o_ai vec_nand(vector signed int __a, + vector signed int __b) { + return ~(__a & __b); +} + +static vector signed int __ATTRS_o_ai vec_nand(vector signed int __a, + vector bool int __b) { + return ~(__a & __b); +} + +static vector signed int __ATTRS_o_ai vec_nand(vector bool int __a, + vector signed int __b) { + return ~(__a & __b); +} + +static vector unsigned int __ATTRS_o_ai vec_nand(vector unsigned int __a, + vector unsigned int __b) { + return ~(__a & __b); +} + +static vector unsigned int __ATTRS_o_ai vec_nand(vector unsigned int __a, + vector bool int __b) { + return ~(__a & __b); +} + +static vector unsigned int __ATTRS_o_ai vec_nand(vector bool int __a, + vector unsigned int __b) { + return ~(__a & __b); +} + +static vector signed long long __ATTRS_o_ai +vec_nand(vector signed long long __a, vector signed long long __b) { + return ~(__a & __b); +} + +static vector signed long long __ATTRS_o_ai +vec_nand(vector signed long long __a, vector bool long long __b) { + return ~(__a & __b); +} + +static vector signed long long __ATTRS_o_ai +vec_nand(vector bool long long __a, vector signed long long __b) { + return ~(__a & __b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_nand(vector unsigned long long __a, vector unsigned long long __b) { + return ~(__a & __b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_nand(vector unsigned long long __a, vector bool long long __b) { + return ~(__a & __b); +} + +static vector unsigned long long __ATTRS_o_ai +vec_nand(vector bool long long __a, vector unsigned long long __b) { + return ~(__a & __b); +} + +#endif + +/* vec_nmadd */ + +#ifdef __VSX__ +static vector float __ATTRS_o_ai +vec_nmadd(vector float __a, vector float __b, vector float __c) { + return __builtin_vsx_xvnmaddasp(__a, __b, __c); +} + +static vector double __ATTRS_o_ai +vec_nmadd(vector double __a, vector double __b, vector double __c) { + return __builtin_vsx_xvnmaddadp(__a, __b, __c); +} +#endif + /* vec_nmsub */ -static vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_nmsub(vector float __a, vector float __b, vector float __c) { +#ifdef __VSX__ + return __builtin_vsx_xvnmsubasp(__a, __b, __c); +#else return __builtin_altivec_vnmsubfp(__a, __b, __c); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_nmsub(vector double __a, vector double __b, vector double __c) { + return __builtin_vsx_xvnmsubadp(__a, __b, __c); } +#endif /* vec_vnmsubfp */ @@ -3949,6 +4625,15 @@ static vector float __ATTRS_o_ai vec_nor(vector float __a, vector float __b) { return (vector float)__res; } +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_nor(vector double __a, vector double __b) { + vector unsigned long long __res = + ~((vector unsigned long long)__a | (vector unsigned long long)__b); + return (vector double)__res; +} +#endif + /* vec_vnor */ static vector signed char __ATTRS_o_ai vec_vnor(vector signed char __a, @@ -4141,6 +4826,22 @@ static vector float __ATTRS_o_ai vec_or(vector float __a, vector bool int __b) { } #ifdef __VSX__ +static vector double __ATTRS_o_ai vec_or(vector bool long long __a, + vector double __b) { + return (vector unsigned long long)__a | (vector unsigned long long)__b; +} + +static vector double __ATTRS_o_ai vec_or(vector double __a, + vector bool long long __b) { + return (vector unsigned long long)__a | (vector unsigned long long)__b; +} + +static vector double __ATTRS_o_ai vec_or(vector double __a, vector double __b) { + vector unsigned long long __res = + (vector unsigned long long)__a | (vector unsigned long long)__b; + return (vector double)__res; +} + static vector signed long long __ATTRS_o_ai vec_or(vector signed long long __a, vector signed long long __b) { return __a | __b; @@ -4177,6 +4878,128 @@ static vector bool long long __ATTRS_o_ai vec_or(vector bool long long __a, } #endif +#ifdef __POWER8_VECTOR__ +static vector signed char __ATTRS_o_ai vec_orc(vector signed char __a, + vector signed char __b) { + return __a | ~__b; +} + +static vector signed char __ATTRS_o_ai vec_orc(vector signed char __a, + vector bool char __b) { + return __a | ~__b; +} + +static vector signed char __ATTRS_o_ai vec_orc(vector bool char __a, + vector signed char __b) { + return __a | ~__b; +} + +static vector unsigned char __ATTRS_o_ai vec_orc(vector unsigned char __a, + vector unsigned char __b) { + return __a | ~__b; +} + +static vector unsigned char __ATTRS_o_ai vec_orc(vector unsigned char __a, + vector bool char __b) { + return __a | ~__b; +} + +static vector unsigned char __ATTRS_o_ai vec_orc(vector bool char __a, + vector unsigned char __b) { + return __a | ~__b; +} + +static vector signed short __ATTRS_o_ai vec_orc(vector signed short __a, + vector signed short __b) { + return __a | ~__b; +} + +static vector signed short __ATTRS_o_ai vec_orc(vector signed short __a, + vector bool short __b) { + return __a | ~__b; +} + +static vector signed short __ATTRS_o_ai vec_orc(vector bool short __a, + vector signed short __b) { + return __a | ~__b; +} + +static vector unsigned short __ATTRS_o_ai vec_orc(vector unsigned short __a, + vector unsigned short __b) { + return __a | ~__b; +} + +static vector unsigned short __ATTRS_o_ai vec_orc(vector unsigned short __a, + vector bool short __b) { + return __a | ~__b; +} + +static vector unsigned short __ATTRS_o_ai +vec_orc(vector bool short __a, vector unsigned short __b) { + return __a | ~__b; +} + +static vector signed int __ATTRS_o_ai vec_orc(vector signed int __a, + vector signed int __b) { + return __a | ~__b; +} + +static vector signed int __ATTRS_o_ai vec_orc(vector signed int __a, + vector bool int __b) { + return __a | ~__b; +} + +static vector signed int __ATTRS_o_ai vec_orc(vector bool int __a, + vector signed int __b) { + return __a | ~__b; +} + +static vector unsigned int __ATTRS_o_ai vec_orc(vector unsigned int __a, + vector unsigned int __b) { + return __a | ~__b; +} + +static vector unsigned int __ATTRS_o_ai vec_orc(vector unsigned int __a, + vector bool int __b) { + return __a | ~__b; +} + +static vector unsigned int __ATTRS_o_ai vec_orc(vector bool int __a, + vector unsigned int __b) { + return __a | ~__b; +} + +static vector signed long long __ATTRS_o_ai +vec_orc(vector signed long long __a, vector signed long long __b) { + return __a | ~__b; +} + +static vector signed long long __ATTRS_o_ai vec_orc(vector signed long long __a, + vector bool long long __b) { + return __a | ~__b; +} + +static vector signed long long __ATTRS_o_ai +vec_orc(vector bool long long __a, vector signed long long __b) { + return __a | ~__b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_orc(vector unsigned long long __a, vector unsigned long long __b) { + return __a | ~__b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_orc(vector unsigned long long __a, vector bool long long __b) { + return __a | ~__b; +} + +static vector unsigned long long __ATTRS_o_ai +vec_orc(vector bool long long __a, vector unsigned long long __b) { + return __a | ~__b; +} +#endif + /* vec_vor */ static vector signed char __ATTRS_o_ai vec_vor(vector signed char __a, @@ -4431,6 +5254,53 @@ static vector bool short __ATTRS_o_ai vec_pack(vector bool int __a, #endif } +#ifdef __VSX__ +static vector signed int __ATTRS_o_ai vec_pack(vector signed long long __a, + vector signed long long __b) { +#ifdef __LITTLE_ENDIAN__ + return (vector signed int)vec_perm( + __a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0A, 0x0B, + 0x10, 0x11, 0x12, 0x13, 0x18, 0x19, 0x1A, 0x1B)); +#else + return (vector signed int)vec_perm( + __a, __b, + (vector unsigned char)(0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F, + 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F)); +#endif +} +static vector unsigned int __ATTRS_o_ai +vec_pack(vector unsigned long long __a, vector unsigned long long __b) { +#ifdef __LITTLE_ENDIAN__ + return (vector unsigned int)vec_perm( + __a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0A, 0x0B, + 0x10, 0x11, 0x12, 0x13, 0x18, 0x19, 0x1A, 0x1B)); +#else + return (vector unsigned int)vec_perm( + __a, __b, + (vector unsigned char)(0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F, + 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F)); +#endif +} + +static vector bool int __ATTRS_o_ai vec_pack(vector bool long long __a, + vector bool long long __b) { +#ifdef __LITTLE_ENDIAN__ + return (vector bool int)vec_perm( + __a, __b, + (vector unsigned char)(0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0A, 0x0B, + 0x10, 0x11, 0x12, 0x13, 0x18, 0x19, 0x1A, 0x1B)); +#else + return (vector bool int)vec_perm( + __a, __b, + (vector unsigned char)(0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F, + 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F)); +#endif +} + +#endif + /* vec_vpkuhum */ #define __builtin_altivec_vpkuhum vec_vpkuhum @@ -4895,17 +5765,18 @@ static vector bool char __ATTRS_o_ai vec_perm(vector bool char __a, #endif } -static vector short __ATTRS_o_ai vec_perm(vector short __a, vector short __b, +static vector short __ATTRS_o_ai vec_perm(vector signed short __a, + vector signed short __b, vector unsigned char __c) { #ifdef __LITTLE_ENDIAN__ vector unsigned char __d = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; __d = vec_xor(__c, __d); - return (vector short)__builtin_altivec_vperm_4si((vector int)__b, - (vector int)__a, __d); + return (vector signed short)__builtin_altivec_vperm_4si((vector int)__b, + (vector int)__a, __d); #else - return (vector short)__builtin_altivec_vperm_4si((vector int)__a, - (vector int)__b, __c); + return (vector signed short)__builtin_altivec_vperm_4si((vector int)__a, + (vector int)__b, __c); #endif } @@ -4953,15 +5824,16 @@ static vector pixel __ATTRS_o_ai vec_perm(vector pixel __a, vector pixel __b, #endif } -static vector int __ATTRS_o_ai vec_perm(vector int __a, vector int __b, +static vector int __ATTRS_o_ai vec_perm(vector signed int __a, + vector signed int __b, vector unsigned char __c) { #ifdef __LITTLE_ENDIAN__ vector unsigned char __d = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; __d = vec_xor(__c, __d); - return (vector int)__builtin_altivec_vperm_4si(__b, __a, __d); + return (vector signed int)__builtin_altivec_vperm_4si(__b, __a, __d); #else - return (vector int)__builtin_altivec_vperm_4si(__a, __b, __c); + return (vector signed int)__builtin_altivec_vperm_4si(__a, __b, __c); #endif } @@ -5010,16 +5882,18 @@ static vector float __ATTRS_o_ai vec_perm(vector float __a, vector float __b, } #ifdef __VSX__ -static vector long long __ATTRS_o_ai vec_perm(vector long long __a, - vector long long __b, +static vector long long __ATTRS_o_ai vec_perm(vector signed long long __a, + vector signed long long __b, vector unsigned char __c) { #ifdef __LITTLE_ENDIAN__ vector unsigned char __d = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; __d = vec_xor(__c, __d); - return (vector long long)__builtin_altivec_vperm_4si(__b, __a, __d); + return (vector signed long long)__builtin_altivec_vperm_4si( + (vector int)__b, (vector int)__a, __d); #else - return (vector long long)__builtin_altivec_vperm_4si(__a, __b, __c); + return (vector signed long long)__builtin_altivec_vperm_4si( + (vector int)__a, (vector int)__b, __c); #endif } @@ -5038,6 +5912,21 @@ vec_perm(vector unsigned long long __a, vector unsigned long long __b, #endif } +static vector bool long long __ATTRS_o_ai +vec_perm(vector bool long long __a, vector bool long long __b, + vector unsigned char __c) { +#ifdef __LITTLE_ENDIAN__ + vector unsigned char __d = {255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255}; + __d = vec_xor(__c, __d); + return (vector bool long long)__builtin_altivec_vperm_4si( + (vector int)__b, (vector int)__a, __d); +#else + return (vector bool long long)__builtin_altivec_vperm_4si( + (vector int)__a, (vector int)__b, __c); +#endif +} + static vector double __ATTRS_o_ai vec_perm(vector double __a, vector double __b, vector unsigned char __c) { #ifdef __LITTLE_ENDIAN__ @@ -5139,10 +6028,20 @@ static vector double __ATTRS_o_ai vec_vperm(vector double __a, /* vec_re */ -static vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_re(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvresp(__a); +#else return __builtin_altivec_vrefp(__a); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_re(vector double __a) { + return __builtin_vsx_xvredp(__a); } +#endif /* vec_vrefp */ @@ -5232,10 +6131,41 @@ static vector unsigned int __ATTRS_o_ai vec_vrlw(vector unsigned int __a, /* vec_round */ -static vector float __attribute__((__always_inline__)) -vec_round(vector float __a) { +static vector float __ATTRS_o_ai vec_round(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvrspi(__a); +#else return __builtin_altivec_vrfin(__a); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_round(vector double __a) { + return __builtin_vsx_xvrdpi(__a); +} + +/* vec_rint */ + +static vector float __ATTRS_o_ai +vec_rint(vector float __a) { + return __builtin_vsx_xvrspic(__a); +} + +static vector double __ATTRS_o_ai +vec_rint(vector double __a) { + return __builtin_vsx_xvrdpic(__a); +} + +/* vec_nearbyint */ + +static vector float __ATTRS_o_ai vec_nearbyint(vector float __a) { + return __builtin_vsx_xvrspi(__a); +} + +static vector double __ATTRS_o_ai vec_nearbyint(vector double __a) { + return __builtin_vsx_xvrdpi(__a); } +#endif /* vec_vrfin */ @@ -5244,12 +6174,34 @@ vec_vrfin(vector float __a) { return __builtin_altivec_vrfin(__a); } +/* vec_sqrt */ + +#ifdef __VSX__ +static vector float __ATTRS_o_ai vec_sqrt(vector float __a) { + return __builtin_vsx_xvsqrtsp(__a); +} + +static vector double __ATTRS_o_ai vec_sqrt(vector double __a) { + return __builtin_vsx_xvsqrtdp(__a); +} +#endif + /* vec_rsqrte */ -static __vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_rsqrte(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvrsqrtesp(__a); +#else return __builtin_altivec_vrsqrtefp(__a); +#endif +} + +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_rsqrte(vector double __a) { + return __builtin_vsx_xvrsqrtedp(__a); } +#endif /* vec_vrsqrtefp */ @@ -5381,6 +6333,22 @@ static vector float __ATTRS_o_ai vec_sel(vector float __a, vector float __b, return (vector float)__res; } +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_sel(vector double __a, vector double __b, + vector bool long long __c) { + vector long long __res = ((vector long long)__a & ~(vector long long)__c) | + ((vector long long)__b & (vector long long)__c); + return (vector double)__res; +} + +static vector double __ATTRS_o_ai vec_sel(vector double __a, vector double __b, + vector unsigned long long __c) { + vector long long __res = ((vector long long)__a & ~(vector long long)__c) | + ((vector long long)__b & (vector long long)__c); + return (vector double)__res; +} +#endif + /* vec_vsel */ static vector signed char __ATTRS_o_ai vec_vsel(vector signed char __a, @@ -5593,78 +6561,121 @@ static vector unsigned int __ATTRS_o_ai vec_vslw(vector unsigned int __a, static vector signed char __ATTRS_o_ai vec_sld(vector signed char __a, vector signed char __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector unsigned char __ATTRS_o_ai vec_sld(vector unsigned char __a, vector unsigned char __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } -static vector short __ATTRS_o_ai vec_sld(vector short __a, vector short __b, - unsigned char __c) { +static vector bool char __ATTRS_o_ai vec_sld(vector bool char __a, + vector bool char __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); +} + +static vector signed short __ATTRS_o_ai vec_sld(vector signed short __a, + vector signed short __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; + return vec_perm( + __a, __b, + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector unsigned short __ATTRS_o_ai vec_sld(vector unsigned short __a, vector unsigned short __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); +} + +static vector bool short __ATTRS_o_ai vec_sld(vector bool short __a, + vector bool short __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; + return vec_perm( + __a, __b, + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector pixel __ATTRS_o_ai vec_sld(vector pixel __a, vector pixel __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } -static vector int __ATTRS_o_ai vec_sld(vector int __a, vector int __b, - unsigned char __c) { +static vector signed int __ATTRS_o_ai vec_sld(vector signed int __a, + vector signed int __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector unsigned int __ATTRS_o_ai vec_sld(vector unsigned int __a, vector unsigned int __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); +} + +static vector bool int __ATTRS_o_ai vec_sld(vector bool int __a, + vector bool int __b, + unsigned const int __c) { + unsigned char __d = __c & 0x0F; + return vec_perm( + __a, __b, + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } static vector float __ATTRS_o_ai vec_sld(vector float __a, vector float __b, - unsigned char __c) { + unsigned const int __c) { + unsigned char __d = __c & 0x0F; return vec_perm( __a, __b, - (vector unsigned char)(__c, __c + 1, __c + 2, __c + 3, __c + 4, __c + 5, - __c + 6, __c + 7, __c + 8, __c + 9, __c + 10, - __c + 11, __c + 12, __c + 13, __c + 14, __c + 15)); + (vector unsigned char)(__d, __d + 1, __d + 2, __d + 3, __d + 4, __d + 5, + __d + 6, __d + 7, __d + 8, __d + 9, __d + 10, + __d + 11, __d + 12, __d + 13, __d + 14, __d + 15)); } /* vec_vsldoi */ @@ -6273,91 +7284,131 @@ static vector float __ATTRS_o_ai vec_vslo(vector float __a, /* vec_splat */ static vector signed char __ATTRS_o_ai vec_splat(vector signed char __a, - unsigned char __b) { - return vec_perm(__a, __a, (vector unsigned char)(__b)); + unsigned const int __b) { + return vec_perm(__a, __a, (vector unsigned char)(__b & 0x0F)); } static vector unsigned char __ATTRS_o_ai vec_splat(vector unsigned char __a, - unsigned char __b) { - return vec_perm(__a, __a, (vector unsigned char)(__b)); + unsigned const int __b) { + return vec_perm(__a, __a, (vector unsigned char)(__b & 0x0F)); } static vector bool char __ATTRS_o_ai vec_splat(vector bool char __a, - unsigned char __b) { - return vec_perm(__a, __a, (vector unsigned char)(__b)); + unsigned const int __b) { + return vec_perm(__a, __a, (vector unsigned char)(__b & 0x0F)); } -static vector short __ATTRS_o_ai vec_splat(vector short __a, - unsigned char __b) { - __b *= 2; - unsigned char b1 = __b + 1; +static vector signed short __ATTRS_o_ai vec_splat(vector signed short __a, + unsigned const int __b) { + unsigned char b0 = (__b & 0x07) * 2; + unsigned char b1 = b0 + 1; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, __b, b1, __b, b1, __b, b1, - __b, b1, __b, b1, __b, b1, __b, b1)); + (vector unsigned char)(b0, b1, b0, b1, b0, b1, b0, b1, + b0, b1, b0, b1, b0, b1, b0, b1)); } static vector unsigned short __ATTRS_o_ai vec_splat(vector unsigned short __a, - unsigned char __b) { - __b *= 2; - unsigned char b1 = __b + 1; + unsigned const int __b) { + unsigned char b0 = (__b & 0x07) * 2; + unsigned char b1 = b0 + 1; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, __b, b1, __b, b1, __b, b1, - __b, b1, __b, b1, __b, b1, __b, b1)); + (vector unsigned char)(b0, b1, b0, b1, b0, b1, b0, b1, + b0, b1, b0, b1, b0, b1, b0, b1)); } static vector bool short __ATTRS_o_ai vec_splat(vector bool short __a, - unsigned char __b) { - __b *= 2; - unsigned char b1 = __b + 1; + unsigned const int __b) { + unsigned char b0 = (__b & 0x07) * 2; + unsigned char b1 = b0 + 1; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, __b, b1, __b, b1, __b, b1, - __b, b1, __b, b1, __b, b1, __b, b1)); + (vector unsigned char)(b0, b1, b0, b1, b0, b1, b0, b1, + b0, b1, b0, b1, b0, b1, b0, b1)); } static vector pixel __ATTRS_o_ai vec_splat(vector pixel __a, - unsigned char __b) { - __b *= 2; - unsigned char b1 = __b + 1; + unsigned const int __b) { + unsigned char b0 = (__b & 0x07) * 2; + unsigned char b1 = b0 + 1; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, __b, b1, __b, b1, __b, b1, - __b, b1, __b, b1, __b, b1, __b, b1)); + (vector unsigned char)(b0, b1, b0, b1, b0, b1, b0, b1, + b0, b1, b0, b1, b0, b1, b0, b1)); } -static vector int __ATTRS_o_ai vec_splat(vector int __a, unsigned char __b) { - __b *= 4; - unsigned char b1 = __b + 1, b2 = __b + 2, b3 = __b + 3; +static vector signed int __ATTRS_o_ai vec_splat(vector signed int __a, + unsigned const int __b) { + unsigned char b0 = (__b & 0x03) * 4; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, b2, b3, __b, b1, b2, b3, __b, - b1, b2, b3, __b, b1, b2, b3)); + (vector unsigned char)(b0, b1, b2, b3, b0, b1, b2, b3, b0, + b1, b2, b3, b0, b1, b2, b3)); } static vector unsigned int __ATTRS_o_ai vec_splat(vector unsigned int __a, - unsigned char __b) { - __b *= 4; - unsigned char b1 = __b + 1, b2 = __b + 2, b3 = __b + 3; + unsigned const int __b) { + unsigned char b0 = (__b & 0x03) * 4; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, b2, b3, __b, b1, b2, b3, __b, - b1, b2, b3, __b, b1, b2, b3)); + (vector unsigned char)(b0, b1, b2, b3, b0, b1, b2, b3, b0, + b1, b2, b3, b0, b1, b2, b3)); } static vector bool int __ATTRS_o_ai vec_splat(vector bool int __a, - unsigned char __b) { - __b *= 4; - unsigned char b1 = __b + 1, b2 = __b + 2, b3 = __b + 3; + unsigned const int __b) { + unsigned char b0 = (__b & 0x03) * 4; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, b2, b3, __b, b1, b2, b3, __b, - b1, b2, b3, __b, b1, b2, b3)); + (vector unsigned char)(b0, b1, b2, b3, b0, b1, b2, b3, b0, + b1, b2, b3, b0, b1, b2, b3)); } static vector float __ATTRS_o_ai vec_splat(vector float __a, - unsigned char __b) { - __b *= 4; - unsigned char b1 = __b + 1, b2 = __b + 2, b3 = __b + 3; + unsigned const int __b) { + unsigned char b0 = (__b & 0x03) * 4; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3; return vec_perm(__a, __a, - (vector unsigned char)(__b, b1, b2, b3, __b, b1, b2, b3, __b, - b1, b2, b3, __b, b1, b2, b3)); + (vector unsigned char)(b0, b1, b2, b3, b0, b1, b2, b3, b0, + b1, b2, b3, b0, b1, b2, b3)); } +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_splat(vector double __a, + unsigned const int __b) { + unsigned char b0 = (__b & 0x01) * 8; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3, b4 = b0 + 4, + b5 = b0 + 5, b6 = b0 + 6, b7 = b0 + 7; + return vec_perm(__a, __a, + (vector unsigned char)(b0, b1, b2, b3, b4, b5, b6, b7, + b0, b1, b2, b3, b4, b5, b6, b7)); +} +static vector bool long long __ATTRS_o_ai vec_splat(vector bool long long __a, + unsigned const int __b) { + unsigned char b0 = (__b & 0x01) * 8; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3, b4 = b0 + 4, + b5 = b0 + 5, b6 = b0 + 6, b7 = b0 + 7; + return vec_perm(__a, __a, + (vector unsigned char)(b0, b1, b2, b3, b4, b5, b6, b7, + b0, b1, b2, b3, b4, b5, b6, b7)); +} +static vector signed long long __ATTRS_o_ai +vec_splat(vector signed long long __a, unsigned const int __b) { + unsigned char b0 = (__b & 0x01) * 8; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3, b4 = b0 + 4, + b5 = b0 + 5, b6 = b0 + 6, b7 = b0 + 7; + return vec_perm(__a, __a, + (vector unsigned char)(b0, b1, b2, b3, b4, b5, b6, b7, + b0, b1, b2, b3, b4, b5, b6, b7)); +} +static vector unsigned long long __ATTRS_o_ai +vec_splat(vector unsigned long long __a, unsigned const int __b) { + unsigned char b0 = (__b & 0x01) * 8; + unsigned char b1 = b0 + 1, b2 = b0 + 2, b3 = b0 + 3, b4 = b0 + 4, + b5 = b0 + 5, b6 = b0 + 6, b7 = b0 + 7; + return vec_perm(__a, __a, + (vector unsigned char)(b0, b1, b2, b3, b4, b5, b6, b7, + b0, b1, b2, b3, b4, b5, b6, b7)); +} +#endif + /* vec_vspltb */ #define __builtin_altivec_vspltb vec_vspltb @@ -6529,7 +7580,8 @@ static vector unsigned int __ATTRS_o_ai vec_splat_u32(signed char __a) { static vector signed char __ATTRS_o_ai vec_sr(vector signed char __a, vector unsigned char __b) { - return __a >> (vector signed char)__b; + vector unsigned char __res = (vector unsigned char)__a >> __b; + return (vector signed char)__res; } static vector unsigned char __ATTRS_o_ai vec_sr(vector unsigned char __a, @@ -6537,9 +7589,10 @@ static vector unsigned char __ATTRS_o_ai vec_sr(vector unsigned char __a, return __a >> __b; } -static vector short __ATTRS_o_ai vec_sr(vector short __a, +static vector signed short __ATTRS_o_ai vec_sr(vector signed short __a, vector unsigned short __b) { - return __a >> (vector short)__b; + vector unsigned short __res = (vector unsigned short)__a >> __b; + return (vector signed short)__res; } static vector unsigned short __ATTRS_o_ai vec_sr(vector unsigned short __a, @@ -6547,8 +7600,10 @@ static vector unsigned short __ATTRS_o_ai vec_sr(vector unsigned short __a, return __a >> __b; } -static vector int __ATTRS_o_ai vec_sr(vector int __a, vector unsigned int __b) { - return __a >> (vector int)__b; +static vector signed int __ATTRS_o_ai vec_sr(vector signed int __a, + vector unsigned int __b) { + vector unsigned int __res = (vector unsigned int)__a >> __b; + return (vector signed int)__res; } static vector unsigned int __ATTRS_o_ai vec_sr(vector unsigned int __a, @@ -6559,7 +7614,8 @@ static vector unsigned int __ATTRS_o_ai vec_sr(vector unsigned int __a, #ifdef __POWER8_VECTOR__ static vector signed long long __ATTRS_o_ai vec_sr(vector signed long long __a, vector unsigned long long __b) { - return __a >> (vector long long)__b; + vector unsigned long long __res = (vector unsigned long long)__a >> __b; + return (vector signed long long)__res; } static vector unsigned long long __ATTRS_o_ai @@ -7960,6 +9016,13 @@ static vector float __ATTRS_o_ai vec_sub(vector float __a, vector float __b) { return __a - __b; } +#ifdef __VSX__ +static vector double __ATTRS_o_ai +vec_sub(vector double __a, vector double __b) { + return __a - __b; +} +#endif + /* vec_vsububm */ #define __builtin_altivec_vsububm vec_vsububm @@ -8451,11 +9514,21 @@ vec_vsumsws(vector signed int __a, vector signed int __b) { /* vec_trunc */ -static vector float __attribute__((__always_inline__)) +static vector float __ATTRS_o_ai vec_trunc(vector float __a) { +#ifdef __VSX__ + return __builtin_vsx_xvrspiz(__a); +#else return __builtin_altivec_vrfiz(__a); +#endif } +#ifdef __VSX__ +static vector double __ATTRS_o_ai vec_trunc(vector double __a) { + return __builtin_vsx_xvrdpiz(__a); +} +#endif + /* vec_vrfiz */ static vector float __attribute__((__always_inline__)) @@ -8945,6 +10018,24 @@ static vector bool long long __ATTRS_o_ai vec_xor(vector bool long long __a, vector bool long long __b) { return __a ^ __b; } + +static vector double __ATTRS_o_ai +vec_xor(vector double __a, vector double __b) { + return (vector double)((vector unsigned long long)__a ^ + (vector unsigned long long)__b); +} + +static vector double __ATTRS_o_ai +vec_xor(vector double __a, vector bool long long __b) { + return (vector double)((vector unsigned long long)__a ^ + (vector unsigned long long) __b); +} + +static vector double __ATTRS_o_ai +vec_xor(vector bool long long __a, vector double __b) { + return (vector double)((vector unsigned long long)__a ^ + (vector unsigned long long)__b); +} #endif /* vec_vxor */ diff --git a/lib/Headers/avx512vlbwintrin.h b/lib/Headers/avx512vlbwintrin.h index 59849e43fd32..eb198a5ade6f 100644 --- a/lib/Headers/avx512vlbwintrin.h +++ b/lib/Headers/avx512vlbwintrin.h @@ -777,6 +777,1051 @@ _mm_maskz_mullo_epi16 (__mmask8 __U, __m128i __A, __m128i __B) { _mm_setzero_si128 (), (__mmask8) __U); } + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_blend_epi8 (__mmask16 __U, __m128i __A, __m128i __W) +{ + return (__m128i) __builtin_ia32_blendmb_128_mask ((__v16qi) __A, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_blend_epi8 (__mmask32 __U, __m256i __A, __m256i __W) +{ + return (__m256i) __builtin_ia32_blendmb_256_mask ((__v32qi) __A, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_blend_epi16 (__mmask8 __U, __m128i __A, __m128i __W) +{ + return (__m128i) __builtin_ia32_blendmw_128_mask ((__v8hi) __A, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_blend_epi16 (__mmask16 __U, __m256i __A, __m256i __W) +{ + return (__m256i) __builtin_ia32_blendmw_256_mask ((__v16hi) __A, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_abs_epi8 (__m128i __W, __mmask16 __U, __m128i __A) +{ + return (__m128i) __builtin_ia32_pabsb128_mask ((__v16qi) __A, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_abs_epi8 (__mmask16 __U, __m128i __A) +{ + return (__m128i) __builtin_ia32_pabsb128_mask ((__v16qi) __A, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_abs_epi8 (__m256i __W, __mmask32 __U, __m256i __A) +{ + return (__m256i) __builtin_ia32_pabsb256_mask ((__v32qi) __A, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_abs_epi8 (__mmask32 __U, __m256i __A) +{ + return (__m256i) __builtin_ia32_pabsb256_mask ((__v32qi) __A, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_abs_epi16 (__m128i __W, __mmask8 __U, __m128i __A) +{ + return (__m128i) __builtin_ia32_pabsw128_mask ((__v8hi) __A, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_abs_epi16 (__mmask8 __U, __m128i __A) +{ + return (__m128i) __builtin_ia32_pabsw128_mask ((__v8hi) __A, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_abs_epi16 (__m256i __W, __mmask16 __U, __m256i __A) +{ + return (__m256i) __builtin_ia32_pabsw256_mask ((__v16hi) __A, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_abs_epi16 (__mmask16 __U, __m256i __A) +{ + return (__m256i) __builtin_ia32_pabsw256_mask ((__v16hi) __A, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_packs_epi32 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_packssdw128_mask ((__v4si) __A, + (__v4si) __B, + (__v8hi) _mm_setzero_si128 (), __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_packs_epi32 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_packssdw128_mask ((__v4si) __A, + (__v4si) __B, + (__v8hi) __W, __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_packs_epi32 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_packssdw256_mask ((__v8si) __A, + (__v8si) __B, + (__v16hi) _mm256_setzero_si256 (), + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_packs_epi32 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_packssdw256_mask ((__v8si) __A, + (__v8si) __B, + (__v16hi) __W, __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_packs_epi16 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_packsswb128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v16qi) _mm_setzero_si128 (), + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_packs_epi16 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_packsswb128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v16qi) __W, + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_packs_epi16 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_packsswb256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v32qi) _mm256_setzero_si256 (), + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_packs_epi16 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_packsswb256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v32qi) __W, + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_packus_epi32 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_packusdw128_mask ((__v4si) __A, + (__v4si) __B, + (__v8hi) _mm_setzero_si128 (), + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_packus_epi32 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_packusdw128_mask ((__v4si) __A, + (__v4si) __B, + (__v8hi) __W, __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_packus_epi32 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_packusdw256_mask ((__v8si) __A, + (__v8si) __B, + (__v16hi) _mm256_setzero_si256 (), + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_packus_epi32 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_packusdw256_mask ((__v8si) __A, + (__v8si) __B, + (__v16hi) __W, + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_packus_epi16 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_packuswb128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v16qi) _mm_setzero_si128 (), + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_packus_epi16 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_packuswb128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v16qi) __W, + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_packus_epi16 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_packuswb256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v32qi) _mm256_setzero_si256 (), + __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_packus_epi16 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_packuswb256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v32qi) __W, + __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_adds_epi8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_paddsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_adds_epi8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_paddsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_adds_epi8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_paddsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_adds_epi8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_paddsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_adds_epi16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_paddsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_adds_epi16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_paddsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_adds_epi16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_paddsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_adds_epi16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_paddsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_adds_epu8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_paddusb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_adds_epu8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_paddusb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_adds_epu8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_paddusb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_adds_epu8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_paddusb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_adds_epu16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_paddusw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_adds_epu16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_paddusw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_adds_epu16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_paddusw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_adds_epu16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_paddusw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_avg_epu8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pavgb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_avg_epu8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pavgb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_avg_epu8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pavgb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_avg_epu8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pavgb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_avg_epu16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pavgw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_avg_epu16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pavgw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_avg_epu16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pavgw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_avg_epu16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pavgw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_max_epi8 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_max_epi8 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_max_epi8 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_max_epi8 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_max_epi16 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_max_epi16 (__m128i __W, __mmask8 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_max_epi16 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_max_epi16 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_max_epu8 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxub128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_max_epu8 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxub128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_max_epu8 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxub256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_max_epu8 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxub256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_max_epu16 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxuw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_max_epu16 (__m128i __W, __mmask8 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pmaxuw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_max_epu16 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxuw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_max_epu16 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pmaxuw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_min_epi8 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pminsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_min_epi8 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pminsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_min_epi8 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pminsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_min_epi8 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pminsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_min_epi16 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pminsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_min_epi16 (__m128i __W, __mmask8 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pminsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_min_epi16 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pminsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_min_epi16 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pminsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_min_epu8 (__mmask16 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pminub128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_min_epu8 (__m128i __W, __mmask16 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pminub128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_min_epu8 (__mmask32 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pminub256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_min_epu8 (__m256i __W, __mmask32 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pminub256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_min_epu16 (__mmask8 __M, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pminuw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_min_epu16 (__m128i __W, __mmask8 __M, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pminuw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_min_epu16 (__mmask16 __M, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pminuw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __M); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_min_epu16 (__m256i __W, __mmask16 __M, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pminuw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __M); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_shuffle_epi8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_pshufb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_shuffle_epi8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_pshufb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_shuffle_epi8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_pshufb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_shuffle_epi8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_pshufb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_subs_epi8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_psubsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_subs_epi8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_psubsb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_subs_epi8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_psubsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_subs_epi8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_psubsb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_subs_epi16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_psubsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_subs_epi16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_psubsw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_subs_epi16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_psubsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_subs_epi16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_psubsw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_subs_epu8 (__m128i __W, __mmask16 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_psubusb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) __W, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_subs_epu8 (__mmask16 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_psubusb128_mask ((__v16qi) __A, + (__v16qi) __B, + (__v16qi) _mm_setzero_si128 (), + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_subs_epu8 (__m256i __W, __mmask32 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_psubusb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) __W, + (__mmask32) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_subs_epu8 (__mmask32 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_psubusb256_mask ((__v32qi) __A, + (__v32qi) __B, + (__v32qi) _mm256_setzero_si256 (), + (__mmask32) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_subs_epu16 (__m128i __W, __mmask8 __U, __m128i __A, + __m128i __B) +{ + return (__m128i) __builtin_ia32_psubusw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) __W, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_subs_epu16 (__mmask8 __U, __m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_psubusw128_mask ((__v8hi) __A, + (__v8hi) __B, + (__v8hi) _mm_setzero_si128 (), + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_subs_epu16 (__m256i __W, __mmask16 __U, __m256i __A, + __m256i __B) +{ + return (__m256i) __builtin_ia32_psubusw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) __W, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_subs_epu16 (__mmask16 __U, __m256i __A, __m256i __B) +{ + return (__m256i) __builtin_ia32_psubusw256_mask ((__v16hi) __A, + (__v16hi) __B, + (__v16hi) _mm256_setzero_si256 (), + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask2_permutex2var_epi16 (__m128i __A, __m128i __I, __mmask8 __U, + __m128i __B) +{ + return (__m128i) __builtin_ia32_vpermi2varhi128_mask ((__v8hi) __A, + (__v8hi) __I /* idx */ , + (__v8hi) __B, + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask2_permutex2var_epi16 (__m256i __A, __m256i __I, + __mmask16 __U, __m256i __B) +{ + return (__m256i) __builtin_ia32_vpermi2varhi256_mask ((__v16hi) __A, + (__v16hi) __I /* idx */ , + (__v16hi) __B, + (__mmask16) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_permutex2var_epi16 (__m128i __A, __m128i __I, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpermt2varhi128_mask ((__v8hi) __I/* idx */, + (__v8hi) __A, + (__v8hi) __B, + (__mmask8) -1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_permutex2var_epi16 (__m128i __A, __mmask8 __U, __m128i __I, + __m128i __B) +{ + return (__m128i) __builtin_ia32_vpermt2varhi128_mask ((__v8hi) __I/* idx */, + (__v8hi) __A, + (__v8hi) __B, + (__mmask8) __U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_permutex2var_epi16 (__mmask8 __U, __m128i __A, __m128i __I, + __m128i __B) +{ + return (__m128i) __builtin_ia32_vpermt2varhi128_maskz ((__v8hi) __I/* idx */, + (__v8hi) __A, + (__v8hi) __B, + (__mmask8) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_permutex2var_epi16 (__m256i __A, __m256i __I, __m256i __B) +{ + return (__m256i) __builtin_ia32_vpermt2varhi256_mask ((__v16hi) __I/* idx */, + (__v16hi) __A, + (__v16hi) __B, + (__mmask16) -1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_permutex2var_epi16 (__m256i __A, __mmask16 __U, + __m256i __I, __m256i __B) +{ + return (__m256i) __builtin_ia32_vpermt2varhi256_mask ((__v16hi) __I/* idx */, + (__v16hi) __A, + (__v16hi) __B, + (__mmask16) __U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_permutex2var_epi16 (__mmask16 __U, __m256i __A, + __m256i __I, __m256i __B) +{ + return (__m256i) __builtin_ia32_vpermt2varhi256_maskz ((__v16hi) __I/* idx */, + (__v16hi) __A, + (__v16hi) __B, + (__mmask16) __U); +} + #define _mm_cmp_epi8_mask(a, b, p) __extension__ ({ \ (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ (__v16qi)(__m128i)(b), \ diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 6c5c64bd266b..b805990eecbf 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -995,7 +995,8 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { return HFI; } -bool HeaderSearch::tryGetFileInfo(const FileEntry *FE, HeaderFileInfo &Result) const { +bool HeaderSearch::tryGetFileInfo(const FileEntry *FE, + HeaderFileInfo &Result) const { if (FE->getUID() >= FileInfo.size()) return false; const HeaderFileInfo &HFI = FileInfo[FE->getUID()]; @@ -1028,7 +1029,7 @@ void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE, HeaderFileInfo &HFI = FileInfo[FE->getUID()]; HFI.isModuleHeader = true; - HFI.isCompilingModuleHeader = isCompilingModuleHeader; + HFI.isCompilingModuleHeader |= isCompilingModuleHeader; HFI.setHeaderRole(Role); } @@ -1058,15 +1059,16 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, // Next, check to see if the file is wrapped with #ifndef guards. If so, and // if the macro that guards it is defined, we know the #include has no effect. if (const IdentifierInfo *ControllingMacro - = FileInfo.getControllingMacro(ExternalLookup)) - // If the include file is part of a module, and we already know what its - // controlling macro is, then we've already parsed it and can safely just - // make it visible. This saves us needing to switch into the visibility - // state of the module just to check whether the macro is defined within it. - if (M || PP.isMacroDefined(ControllingMacro)) { + = FileInfo.getControllingMacro(ExternalLookup)) { + // If the header corresponds to a module, check whether the macro is already + // defined in that module rather than checking in the current set of visible + // modules. + if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M) + : PP.isMacroDefined(ControllingMacro)) { ++NumMultiIncludeFileOptzn; return false; } + } // Increment the number of times this file has been included. ++FileInfo.NumIncludes; diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index e6fe38927e26..96d3e4b8fe65 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -347,7 +347,7 @@ ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) { // Iterate over all modules that 'File' is part of to find the best fit. for (KnownHeader &H : Known->second) { // Prefer a header from the current module over all others. - if (H.getModule() == CompilingModule) + if (H.getModule()->getTopLevelModule() == CompilingModule) return MakeResult(H); // Cannot use a module if it is unavailable. if (!H.getModule()->isAvailable()) @@ -1528,7 +1528,7 @@ void ModuleMapParser::parseModuleDecl() { /// 'extern' 'module' module-id string-literal void ModuleMapParser::parseExternModuleDecl() { assert(Tok.is(MMToken::ExternKeyword)); - consumeToken(); // 'extern' keyword + SourceLocation ExternLoc = consumeToken(); // 'extern' keyword // Parse 'module' keyword. if (!Tok.is(MMToken::ModuleKeyword)) { @@ -1567,7 +1567,7 @@ void ModuleMapParser::parseExternModuleDecl() { File, /*IsSystem=*/false, Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd ? Directory - : File->getDir()); + : File->getDir(), ExternLoc); } /// \brief Parse a requires declaration. @@ -2319,7 +2319,8 @@ bool ModuleMapParser::parseModuleMapFile() { } bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem, - const DirectoryEntry *Dir) { + const DirectoryEntry *Dir, + SourceLocation ExternModuleLoc) { llvm::DenseMap<const FileEntry *, bool>::iterator Known = ParsedModuleMap.find(File); if (Known != ParsedModuleMap.end()) @@ -2327,7 +2328,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem, assert(Target && "Missing target information"); auto FileCharacter = IsSystem ? SrcMgr::C_System : SrcMgr::C_User; - FileID ID = SourceMgr.createFileID(File, SourceLocation(), FileCharacter); + FileID ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter); const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID); if (!Buffer) return ParsedModuleMap[File] = true; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index d52519e3313b..64ce8c918258 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -1088,6 +1088,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("objc_default_synthesize_properties", LangOpts.ObjC2) .Case("objc_fixed_enum", LangOpts.ObjC2) .Case("objc_instancetype", LangOpts.ObjC2) + .Case("objc_kindof", LangOpts.ObjC2) .Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules) .Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile()) .Case("objc_property_explicit_atomic", @@ -1106,6 +1107,8 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("arc_cf_code_audited", true) .Case("objc_bridge_id", true) .Case("objc_bridge_id_on_typedefs", true) + .Case("objc_generics", LangOpts.ObjC2) + .Case("objc_generics_variance", LangOpts.ObjC2) // C11 features .Case("c_alignas", LangOpts.C11) .Case("c_alignof", LangOpts.C11) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d843e801b634..f46af889e25d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -365,7 +365,8 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, // These may refer to the function arguments, but need to be parsed early to // participate in determining whether it's a redeclaration. std::unique_ptr<ParseScope> PrototypeScope; - if (AttrName->isStr("enable_if") && D && D->isFunctionDeclarator()) { + if (normalizeAttrName(AttrName->getName()) == "enable_if" && + D && D->isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo(); PrototypeScope.reset(new ParseScope(this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | @@ -2144,8 +2145,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) { Diag(Tok, diag::err_expected_type); DS.SetTypeSpecError(); - } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && - !DS.hasAttributes()) { + } else if (Specs == DeclSpec::PQ_None && !DS.hasAttributes()) { Diag(Tok, diag::err_typename_requires_specqual); if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); @@ -2602,6 +2602,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, /// [C11] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] /// [Clang] '__module_private__' declaration-specifiers[opt] +/// [ObjC1] '__kindof' declaration-specifiers[opt] /// /// storage-class-specifier: [C99 6.7.1] /// 'typedef' @@ -2886,12 +2887,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // The typename - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); - continue; } @@ -2997,11 +2992,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // The identifier - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); + // Objective-C supports type arguments and protocol references + // following an Objective-C object or object pointer + // type. Handle either one of them. + if (Tok.is(tok::less) && getLangOpts().ObjC1) { + SourceLocation NewEndLoc; + TypeResult NewTypeRep = parseObjCTypeArgsAndProtocolQualifiers( + Loc, TypeRep, /*consumeLastToken=*/true, + NewEndLoc); + if (NewTypeRep.isUsable()) { + DS.UpdateTypeRep(NewTypeRep.get()); + DS.SetRangeEnd(NewEndLoc); + } + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. @@ -3082,6 +3085,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseNullabilityTypeSpecifiers(DS.getAttributes()); continue; + // Objective-C 'kindof' types. + case tok::kw___kindof: + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, + nullptr, 0, AttributeList::AS_Keyword); + (void)ConsumeToken(); + continue; + // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc, @@ -3418,10 +3428,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1) goto DoneWithDeclSpec; - if (!ParseObjCProtocolQualifiers(DS)) - Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) - << FixItHint::CreateInsertion(Loc, "id") - << SourceRange(Loc, DS.getSourceRange().getEnd()); + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + TypeResult Type = parseObjCProtocolQualifierType(EndLoc); + if (Type.isUsable()) { + if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, StartLoc, + PrevSpec, DiagID, Type.get(), + Actions.getASTContext().getPrintingPolicy())) + Diag(StartLoc, DiagID) << PrevSpec; + + DS.SetRangeEnd(EndLoc); + } else { + DS.SetTypeSpecError(); + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. @@ -4335,6 +4354,8 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw__Nullable: case tok::kw__Null_unspecified: + case tok::kw___kindof: + case tok::kw___private: case tok::kw___local: case tok::kw___global: @@ -4515,6 +4536,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw__Nullable: case tok::kw__Null_unspecified: + case tok::kw___kindof: + case tok::kw___private: case tok::kw___local: case tok::kw___global: @@ -4752,6 +4775,13 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, ParseNullabilityTypeSpecifiers(DS.getAttributes()); continue; + // Objective-C 'kindof' types. + case tok::kw___kindof: + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, + nullptr, 0, AttributeList::AS_Keyword); + (void)ConsumeToken(); + continue; + case tok::kw___attribute: if (AttrReqs & AR_GNUAttributesParsedAndRejected) // When GNU attributes are expressly forbidden, diagnose their usage. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 568896db42be..e347d4e27e26 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -543,10 +543,11 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, SourceLocation IdLoc = ConsumeToken(); ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII); Name.setConstructorName(Type, IdLoc, IdLoc); - } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/ false, - /*AllowDestructorName=*/ true, - /*AllowConstructorName=*/ true, ParsedType(), - TemplateKWLoc, Name)) { + } else if (ParseUnqualifiedId( + SS, /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/NextToken().isNot(tok::equal), + ParsedType(), TemplateKWLoc, Name)) { SkipUntil(tok::semi); return nullptr; } @@ -2814,16 +2815,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, break; } - if ((S->getFlags() & Scope::FnScope)) { - // If we're in a function or function template declared in the - // body of a class, then this is a local class rather than a - // nested class. - const Scope *Parent = S->getParent(); - if (Parent->isTemplateParamScope()) - Parent = Parent->getParent(); - if (Parent->isClassScope()) - break; - } + if ((S->getFlags() & Scope::FnScope)) + // If we're in a function or function template then this is a local + // class rather than a nested class. + break; } } @@ -3813,7 +3808,7 @@ SourceLocation Parser::SkipCXX11Attributes() { return EndLoc; } -/// Parse one or more Microsoft-style attributes [Attr] +/// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr] /// /// [MS] ms-attribute: /// '[' token-seq ']' @@ -3829,8 +3824,6 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, // FIXME: If this is actually a C++11 attribute, parse it as one. BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); - if (Tok.is(tok::r_square)) - Diag(T.getOpenLocation(), diag::err_empty_attribute_block); SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch); T.consumeClose(); if (endLoc) diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 02176c410592..c1dafe9b49b1 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1805,13 +1805,6 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. If we don't have Objective-C or a '<', this is - // just a normal reference to a typedef name. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); - DS.Finish(Diags, PP, Policy); return; } diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 42287d68b331..4896ff0d235a 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -252,26 +252,40 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { // Three cases. This is a message send to a type: [type foo] // This is a message send to super: [super foo] // This is a message sent to an expr: [super.bar foo] - switch (Sema::ObjCMessageKind Kind - = Actions.getObjCMessageKind(getCurScope(), II, IILoc, - II == Ident_super, - NextToken().is(tok::period), - ReceiverType)) { + switch (Actions.getObjCMessageKind( + getCurScope(), II, IILoc, II == Ident_super, + NextToken().is(tok::period), ReceiverType)) { case Sema::ObjCSuperMessage: + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), + ParsedType(), + nullptr); + case Sema::ObjCClassMessage: CheckArrayDesignatorSyntax(*this, StartLoc, Desig); - if (Kind == Sema::ObjCSuperMessage) - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, - ConsumeToken(), - ParsedType(), - nullptr); ConsumeToken(); // the identifier if (!ReceiverType) { SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + // Parse type arguments and protocol qualifiers. + if (Tok.is(tok::less)) { + SourceLocation NewEndLoc; + TypeResult NewReceiverType + = parseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType, + /*consumeLastToken=*/true, + NewEndLoc); + if (!NewReceiverType.isUsable()) { + SkipUntil(tok::r_square, StopAtSemi); + return ExprError(); + } + + ReceiverType = NewReceiverType.get(); + } + + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, SourceLocation(), ReceiverType, nullptr); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index f975f8715ed9..ed6090453daa 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -96,14 +96,17 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { /// /// objc-class-declaration: -/// '@' 'class' identifier-list ';' +/// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';' +/// +/// objc-class-forward-decl: +/// identifier objc-type-parameter-list[opt] /// Parser::DeclGroupPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ConsumeToken(); // the identifier "class" SmallVector<IdentifierInfo *, 8> ClassNames; SmallVector<SourceLocation, 8> ClassLocs; - + SmallVector<ObjCTypeParamList *, 8> ClassTypeParams; while (1) { MaybeSkipAttributes(tok::objc_class); @@ -116,6 +119,14 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ClassLocs.push_back(Tok.getLocation()); ConsumeToken(); + // Parse the optional objc-type-parameter-list. + ObjCTypeParamList *TypeParams = nullptr; + if (Tok.is(tok::less)) { + TypeParams = parseObjCTypeParamList(); + if (TypeParams) + Actions.popObjCTypeParamList(getCurScope(), TypeParams); + } + ClassTypeParams.push_back(TypeParams); if (!TryConsumeToken(tok::comma)) break; } @@ -126,6 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(), ClassLocs.data(), + ClassTypeParams, ClassNames.size()); } @@ -154,20 +166,20 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc) /// objc-category-interface /// /// objc-class-interface: -/// '@' 'interface' identifier objc-superclass[opt] -/// objc-protocol-refs[opt] +/// '@' 'interface' identifier objc-type-parameter-list[opt] +/// objc-superclass[opt] objc-protocol-refs[opt] /// objc-class-instance-variables[opt] /// objc-interface-decl-list /// @end /// /// objc-category-interface: -/// '@' 'interface' identifier '(' identifier[opt] ')' -/// objc-protocol-refs[opt] +/// '@' 'interface' identifier objc-type-parameter-list[opt] +/// '(' identifier[opt] ')' objc-protocol-refs[opt] /// objc-interface-decl-list /// @end /// /// objc-superclass: -/// ':' identifier +/// ':' identifier objc-type-arguments[opt] /// /// objc-class-interface-attributes: /// __attribute__((visibility("default"))) @@ -202,7 +214,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); - if (Tok.is(tok::l_paren) && + + // Parse the objc-type-parameter-list or objc-protocol-refs. For the latter + // case, LAngleLoc will be valid and ProtocolIdents will capture the + // protocol references (that have not yet been resolved). + SourceLocation LAngleLoc, EndProtoLoc; + SmallVector<IdentifierLocPair, 8> ProtocolIdents; + ObjCTypeParamList *typeParameterList = nullptr; + if (Tok.is(tok::less)) { + typeParameterList = parseObjCTypeParamListOrProtocolRefs(LAngleLoc, + ProtocolIdents, + EndProtoLoc); + } + + if (Tok.is(tok::l_paren) && !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category. BalancedDelimiterTracker T(*this, tok::l_paren); @@ -237,17 +262,19 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, } // Next, we need to check for any protocol references. - SourceLocation LAngleLoc, EndProtoLoc; + assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols"); SmallVector<Decl *, 8> ProtocolRefs; SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true, - LAngleLoc, EndProtoLoc)) + LAngleLoc, EndProtoLoc, + /*consumeLastToken=*/true)) return nullptr; Decl *CategoryType = Actions.ActOnStartCategoryInterface(AtLoc, nameId, nameLoc, + typeParameterList, categoryId, categoryLoc, ProtocolRefs.data(), ProtocolRefs.size(), @@ -258,12 +285,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc); ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType); + + if (typeParameterList) + Actions.popObjCTypeParamList(getCurScope(), typeParameterList); + return CategoryType; } // Parse a class interface. IdentifierInfo *superClassId = nullptr; SourceLocation superClassLoc; - + SourceLocation typeArgsLAngleLoc; + SmallVector<ParsedType, 4> typeArgs; + SourceLocation typeArgsRAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; if (Tok.is(tok::colon)) { // a super class is specified. ConsumeToken(); @@ -281,30 +316,64 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, } superClassId = Tok.getIdentifierInfo(); superClassLoc = ConsumeToken(); + + // Type arguments for the superclass or protocol conformances. + if (Tok.is(tok::less)) { + parseObjCTypeArgsOrProtocolQualifiers(ParsedType(), + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + LAngleLoc, + protocols, + protocolLocs, + EndProtoLoc, + /*consumeLastToken=*/true, + /*warnOnIncompleteProtocols=*/true); + } } + // Next, we need to check for any protocol references. - SmallVector<Decl *, 8> ProtocolRefs; - SmallVector<SourceLocation, 8> ProtocolLocs; - SourceLocation LAngleLoc, EndProtoLoc; - if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true, - LAngleLoc, EndProtoLoc)) + if (LAngleLoc.isValid()) { + if (!ProtocolIdents.empty()) { + // We already parsed the protocols named when we thought we had a + // type parameter list. Translate them into actual protocol references. + for (const auto &pair : ProtocolIdents) { + protocolLocs.push_back(pair.second); + } + Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true, + /*ForObjCContainer=*/true, + &ProtocolIdents[0], ProtocolIdents.size(), + protocols); + } + } else if (protocols.empty() && Tok.is(tok::less) && + ParseObjCProtocolReferences(protocols, protocolLocs, true, true, + LAngleLoc, EndProtoLoc, + /*consumeLastToken=*/true)) { return nullptr; + } if (Tok.isNot(tok::less)) - Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc); + Actions.ActOnTypedefedProtocols(protocols, superClassId, superClassLoc); Decl *ClsType = - Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, - superClassId, superClassLoc, - ProtocolRefs.data(), ProtocolRefs.size(), - ProtocolLocs.data(), + Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc, + typeParameterList, superClassId, + superClassLoc, + typeArgs, + SourceRange(typeArgsLAngleLoc, + typeArgsRAngleLoc), + protocols.data(), protocols.size(), + protocolLocs.data(), EndProtoLoc, attrs.getList()); if (Tok.is(tok::l_brace)) ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc); ParseObjCInterfaceDeclList(tok::objc_interface, ClsType); + + if (typeParameterList) + Actions.popObjCTypeParamList(getCurScope(), typeParameterList); + return ClsType; } @@ -339,6 +408,203 @@ static void addContextSensitiveTypeNullability(Parser &P, } } +/// Parse an Objective-C type parameter list, if present, or capture +/// the locations of the protocol identifiers for a list of protocol +/// references. +/// +/// objc-type-parameter-list: +/// '<' objc-type-parameter (',' objc-type-parameter)* '>' +/// +/// objc-type-parameter: +/// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt] +/// +/// objc-type-parameter-bound: +/// ':' type-name +/// +/// objc-type-parameter-variance: +/// '__covariant' +/// '__contravariant' +/// +/// \param lAngleLoc The location of the starting '<'. +/// +/// \param protocolIdents Will capture the list of identifiers, if the +/// angle brackets contain a list of protocol references rather than a +/// type parameter list. +/// +/// \param rAngleLoc The location of the ending '>'. +ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( + SourceLocation &lAngleLoc, + SmallVectorImpl<IdentifierLocPair> &protocolIdents, + SourceLocation &rAngleLoc, + bool mayBeProtocolList) { + assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list"); + + // Within the type parameter list, don't treat '>' as an operator. + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + + // Local function to "flush" the protocol identifiers, turning them into + // type parameters. + SmallVector<Decl *, 4> typeParams; + auto makeProtocolIdentsIntoTypeParameters = [&]() { + unsigned index = 0; + for (const auto &pair : protocolIdents) { + DeclResult typeParam = Actions.actOnObjCTypeParam( + getCurScope(), + ObjCTypeParamVariance::Invariant, + SourceLocation(), + index++, + pair.first, + pair.second, + SourceLocation(), + ParsedType()); + if (typeParam.isUsable()) + typeParams.push_back(typeParam.get()); + } + + protocolIdents.clear(); + mayBeProtocolList = false; + }; + + bool invalid = false; + lAngleLoc = ConsumeToken(); + + do { + // Parse the variance, if any. + SourceLocation varianceLoc; + ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant; + if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) { + variance = Tok.is(tok::kw___covariant) + ? ObjCTypeParamVariance::Covariant + : ObjCTypeParamVariance::Contravariant; + varianceLoc = ConsumeToken(); + + // Once we've seen a variance specific , we know this is not a + // list of protocol references. + if (mayBeProtocolList) { + // Up until now, we have been queuing up parameters because they + // might be protocol references. Turn them into parameters now. + makeProtocolIdentsIntoTypeParameters(); + } + } + + // Parse the identifier. + if (!Tok.is(tok::identifier)) { + // Code completion. + if (Tok.is(tok::code_completion)) { + // FIXME: If these aren't protocol references, we'll need different + // completions. + Actions.CodeCompleteObjCProtocolReferences(protocolIdents.data(), + protocolIdents.size()); + cutOffParsing(); + + // FIXME: Better recovery here?. + return nullptr; + } + + Diag(Tok, diag::err_objc_expected_type_parameter); + invalid = true; + break; + } + + IdentifierInfo *paramName = Tok.getIdentifierInfo(); + SourceLocation paramLoc = ConsumeToken(); + + // If there is a bound, parse it. + SourceLocation colonLoc; + TypeResult boundType; + if (TryConsumeToken(tok::colon, colonLoc)) { + // Once we've seen a bound, we know this is not a list of protocol + // references. + if (mayBeProtocolList) { + // Up until now, we have been queuing up parameters because they + // might be protocol references. Turn them into parameters now. + makeProtocolIdentsIntoTypeParameters(); + } + + // type-name + boundType = ParseTypeName(); + if (boundType.isInvalid()) + invalid = true; + } else if (mayBeProtocolList) { + // If this could still be a protocol list, just capture the identifier. + // We don't want to turn it into a parameter. + protocolIdents.push_back(std::make_pair(paramName, paramLoc)); + continue; + } + + // Create the type parameter. + DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(), + variance, + varianceLoc, + typeParams.size(), + paramName, + paramLoc, + colonLoc, + boundType.isUsable() + ? boundType.get() + : ParsedType()); + if (typeParam.isUsable()) + typeParams.push_back(typeParam.get()); + } while (TryConsumeToken(tok::comma)); + + // Parse the '>'. + if (invalid) { + SkipUntil(tok::greater, tok::at, StopBeforeMatch); + if (Tok.is(tok::greater)) + ConsumeToken(); + } else if (ParseGreaterThanInTemplateList(rAngleLoc, + /*ConsumeLastToken=*/true, + /*ObjCGenericList=*/true)) { + Diag(lAngleLoc, diag::note_matching) << "'<'"; + SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus, + tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace, + tok::comma, tok::semi }, + StopBeforeMatch); + if (Tok.is(tok::greater)) + ConsumeToken(); + } + + if (mayBeProtocolList) { + // A type parameter list must be followed by either a ':' (indicating the + // presence of a superclass) or a '(' (indicating that this is a category + // or extension). This disambiguates between an objc-type-parameter-list + // and a objc-protocol-refs. + if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) { + // Returning null indicates that we don't have a type parameter list. + // The results the caller needs to handle the protocol references are + // captured in the reference parameters already. + return nullptr; + } + + // We have a type parameter list that looks like a list of protocol + // references. Turn that parameter list into type parameters. + makeProtocolIdentsIntoTypeParameters(); + } + + // Form the type parameter list. + ObjCTypeParamList *list = Actions.actOnObjCTypeParamList( + getCurScope(), + lAngleLoc, + typeParams, + rAngleLoc); + + // Clear out the angle locations; they're used by the caller to indicate + // whether there are any protocol references. + lAngleLoc = SourceLocation(); + rAngleLoc = SourceLocation(); + return list; +} + +/// Parse an objc-type-parameter-list. +ObjCTypeParamList *Parser::parseObjCTypeParamList() { + SourceLocation lAngleLoc; + SmallVector<IdentifierLocPair, 1> protocolIdents; + SourceLocation rAngleLoc; + return parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents, + rAngleLoc, + /*mayBeProtocolList=*/false); +} + /// objc-interface-decl-list: /// empty /// objc-interface-decl-list objc-property-decl [OBJC2] @@ -1281,7 +1547,8 @@ bool Parser:: ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, SmallVectorImpl<SourceLocation> &ProtocolLocs, bool WarnOnDeclarations, bool ForObjCContainer, - SourceLocation &LAngleLoc, SourceLocation &EndLoc) { + SourceLocation &LAngleLoc, SourceLocation &EndLoc, + bool consumeLastToken) { assert(Tok.is(tok::less) && "expected <"); LAngleLoc = ConsumeToken(); // the "<" @@ -1311,7 +1578,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, } // Consume the '>'. - if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true)) + if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken, + /*ObjCGenericList=*/false)) return true; // Convert the list of protocols identifiers into a list of protocol decls. @@ -1321,22 +1589,263 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, return false; } -/// \brief Parse the Objective-C protocol qualifiers that follow a typename -/// in a decl-specifier-seq, starting at the '<'. -bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { +TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) { assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'"); assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C"); - SourceLocation LAngleLoc, EndProtoLoc; - SmallVector<Decl *, 8> ProtocolDecl; - SmallVector<SourceLocation, 8> ProtocolLocs; - bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - if (EndProtoLoc.isValid()) - DS.SetRangeEnd(EndProtoLoc); - return Result; + + SourceLocation lAngleLoc; + SmallVector<Decl *, 8> protocols; + SmallVector<SourceLocation, 8> protocolLocs; + (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false, + lAngleLoc, rAngleLoc, + /*consumeLastToken=*/true); + TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc, + protocols, + protocolLocs, + rAngleLoc); + if (result.isUsable()) { + Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id) + << FixItHint::CreateInsertion(lAngleLoc, "id") + << SourceRange(lAngleLoc, rAngleLoc); + } + + return result; +} + +/// Parse Objective-C type arguments or protocol qualifiers. +/// +/// objc-type-arguments: +/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>' +/// +void Parser::parseObjCTypeArgsOrProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken, + bool warnOnIncompleteProtocols) { + assert(Tok.is(tok::less) && "Not at the start of type args or protocols"); + SourceLocation lAngleLoc = ConsumeToken(); + + // Whether all of the elements we've parsed thus far are single + // identifiers, which might be types or might be protocols. + bool allSingleIdentifiers = true; + SmallVector<IdentifierInfo *, 4> identifiers; + SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs; + + // Parse a list of comma-separated identifiers, bailing out if we + // see something different. + do { + // Parse a single identifier. + if (Tok.is(tok::identifier) && + (NextToken().is(tok::comma) || + NextToken().is(tok::greater) || + NextToken().is(tok::greatergreater))) { + identifiers.push_back(Tok.getIdentifierInfo()); + identifierLocs.push_back(ConsumeToken()); + continue; + } + + if (Tok.is(tok::code_completion)) { + // FIXME: Also include types here. + SmallVector<IdentifierLocPair, 4> identifierLocPairs; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + identifierLocPairs.push_back(IdentifierLocPair(identifiers[i], + identifierLocs[i])); + } + + QualType BaseT = Actions.GetTypeFromParser(baseType); + if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); + } else { + Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(), + identifierLocPairs.size()); + } + cutOffParsing(); + return; + } + + allSingleIdentifiers = false; + break; + } while (TryConsumeToken(tok::comma)); + + // If we parsed an identifier list, semantic analysis sorts out + // whether it refers to protocols or to type arguments. + if (allSingleIdentifiers) { + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + /*ObjCGenericList=*/true); + + // Let Sema figure out what we parsed. + Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(), + baseType, + lAngleLoc, + identifiers, + identifierLocs, + rAngleLoc, + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + protocolLAngleLoc, + protocols, + protocolRAngleLoc, + warnOnIncompleteProtocols); + return; + } + + // We syntactically matched a type argument, so commit to parsing + // type arguments. + + // Convert the identifiers into type arguments. + bool invalid = false; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + ParsedType typeArg + = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope()); + if (typeArg) { + DeclSpec DS(AttrFactory); + const char *prevSpec = nullptr; + unsigned diagID; + DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID, + typeArg, Actions.getASTContext().getPrintingPolicy()); + + // Form a declarator to turn this into a type. + Declarator D(DS, Declarator::TypeNameContext); + TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D); + if (fullTypeArg.isUsable()) + typeArgs.push_back(fullTypeArg.get()); + else + invalid = true; + } else { + invalid = true; + } + } + + // Continue parsing type-names. + do { + TypeResult typeArg = ParseTypeName(); + + // Consume the '...' for a pack expansion. + SourceLocation ellipsisLoc; + TryConsumeToken(tok::ellipsis, ellipsisLoc); + if (typeArg.isUsable() && ellipsisLoc.isValid()) { + typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc); + } + + if (typeArg.isUsable()) { + typeArgs.push_back(typeArg.get()); + } else { + invalid = true; + } + } while (TryConsumeToken(tok::comma)); + + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + /*ObjCGenericList=*/true); + + if (invalid) { + typeArgs.clear(); + return; + } + + // Record left/right angle locations. + typeArgsLAngleLoc = lAngleLoc; + typeArgsRAngleLoc = rAngleLoc; +} + +void Parser::parseObjCTypeArgsAndProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken) { + assert(Tok.is(tok::less)); + + // Parse the first angle-bracket-delimited clause. + parseObjCTypeArgsOrProtocolQualifiers(baseType, + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + protocolLAngleLoc, + protocols, + protocolLocs, + protocolRAngleLoc, + consumeLastToken, + /*warnOnIncompleteProtocols=*/false); + + // An Objective-C object pointer followed by type arguments + // can then be followed again by a set of protocol references, e.g., + // \c NSArray<NSView><NSTextDelegate> + if ((consumeLastToken && Tok.is(tok::less)) || + (!consumeLastToken && NextToken().is(tok::less))) { + // If we aren't consuming the last token, the prior '>' is still hanging + // there. Consume it before we parse the protocol qualifiers. + if (!consumeLastToken) + ConsumeToken(); + + if (!protocols.empty()) { + SkipUntilFlags skipFlags = SkipUntilFlags(); + if (!consumeLastToken) + skipFlags = skipFlags | StopBeforeMatch; + Diag(Tok, diag::err_objc_type_args_after_protocols) + << SourceRange(protocolLAngleLoc, protocolRAngleLoc); + SkipUntil(tok::greater, tok::greatergreater, skipFlags); + } else { + ParseObjCProtocolReferences(protocols, protocolLocs, + /*WarnOnDeclarations=*/false, + /*ForObjCContainer=*/false, + protocolLAngleLoc, protocolRAngleLoc, + consumeLastToken); + } + } +} + +TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers( + SourceLocation loc, + ParsedType type, + bool consumeLastToken, + SourceLocation &endLoc) { + assert(Tok.is(tok::less)); + SourceLocation typeArgsLAngleLoc; + SmallVector<ParsedType, 4> typeArgs; + SourceLocation typeArgsRAngleLoc; + SourceLocation protocolLAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; + SourceLocation protocolRAngleLoc; + + // Parse type arguments and protocol qualifiers. + parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs, + typeArgsRAngleLoc, protocolLAngleLoc, + protocols, protocolLocs, + protocolRAngleLoc, consumeLastToken); + + // Compute the location of the last token. + if (consumeLastToken) + endLoc = PrevTokLocation; + else + endLoc = Tok.getLocation(); + + return Actions.actOnObjCTypeArgsAndProtocolQualifiers( + getCurScope(), + loc, + type, + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + protocolLAngleLoc, + protocols, + protocolLocs, + protocolRAngleLoc); } void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc, @@ -1548,7 +2057,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true, - LAngleLoc, EndProtoLoc)) + LAngleLoc, EndProtoLoc, + /*consumeLastToken=*/true)) return DeclGroupPtrTy(); Decl *ProtoType = @@ -1598,6 +2108,22 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { SourceLocation nameLoc = ConsumeToken(); // consume class or category name Decl *ObjCImpDecl = nullptr; + // Neither a type parameter list nor a list of protocol references is + // permitted here. Parse and diagnose them. + if (Tok.is(tok::less)) { + SourceLocation lAngleLoc, rAngleLoc; + SmallVector<IdentifierLocPair, 8> protocolIdents; + SourceLocation diagLoc = Tok.getLocation(); + if (parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents, + rAngleLoc)) { + Diag(diagLoc, diag::err_objc_parameterized_implementation) + << SourceRange(diagLoc, PrevTokLocation); + } else if (lAngleLoc.isValid()) { + Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier) + << FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc)); + } + } + if (Tok.is(tok::l_paren)) { // we have a category implementation. ConsumeParen(); @@ -1626,9 +2152,14 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { rparenLoc = ConsumeParen(); if (Tok.is(tok::less)) { // we have illegal '<' try to recover Diag(Tok, diag::err_unexpected_protocol_qualifier); - AttributeFactory attr; - DeclSpec DS(attr); - (void)ParseObjCProtocolQualifiers(DS); + SourceLocation protocolLAngleLoc, protocolRAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; + (void)ParseObjCProtocolReferences(protocols, protocolLocs, + /*warnOnIncompleteProtocols=*/false, + /*ForObjCContainer=*/false, + protocolLAngleLoc, protocolRAngleLoc, + /*consumeLastToken=*/true); } ObjCImpDecl = Actions.ActOnStartCategoryImplementation( AtLoc, nameId, nameLoc, categoryId, @@ -1656,10 +2187,15 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); else if (Tok.is(tok::less)) { // we have illegal '<' try to recover Diag(Tok, diag::err_unexpected_protocol_qualifier); - // try to recover. - AttributeFactory attr; - DeclSpec DS(attr); - (void)ParseObjCProtocolQualifiers(DS); + + SourceLocation protocolLAngleLoc, protocolRAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; + (void)ParseObjCProtocolReferences(protocols, protocolLocs, + /*warnOnIncompleteProtocols=*/false, + /*ForObjCContainer=*/false, + protocolLAngleLoc, protocolRAngleLoc, + /*consumeLastToken=*/true); } } assert(ObjCImpDecl); @@ -2477,6 +3013,21 @@ ExprResult Parser::ParseObjCMessageExpression() { ConsumeToken(); // the type name + // Parse type arguments and protocol qualifiers. + if (Tok.is(tok::less)) { + SourceLocation NewEndLoc; + TypeResult NewReceiverType + = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType, + /*consumeLastToken=*/true, + NewEndLoc); + if (!NewReceiverType.isUsable()) { + SkipUntil(tok::r_square, StopAtSemi); + return ExprError(); + } + + ReceiverType = NewReceiverType.get(); + } + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), ReceiverType, nullptr); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 2a9becbc8570..3a964dd20528 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -738,11 +738,16 @@ void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, /// /// \param RAngleLoc the location of the consumed '>'. /// -/// \param ConsumeLastToken if true, the '>' is not consumed. +/// \param ConsumeLastToken if true, the '>' is consumed. +/// +/// \param ObjCGenericList if true, this is the '>' closing an Objective-C +/// type parameter or type argument list, rather than a C++ template parameter +/// or argument list. /// /// \returns true, if current token does not start with '>', false otherwise. bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, - bool ConsumeLastToken) { + bool ConsumeLastToken, + bool ObjCGenericList) { // What will be left once we've consumed the '>'. tok::TokenKind RemainingToken; const char *ReplacementStr = "> >"; @@ -783,40 +788,44 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, // the token isn't '>>' or '>>>'. // '>>>' is for CUDA, where this sequence of characters is parsed into // tok::greatergreatergreater, rather than two separate tokens. - + // + // We always allow this for Objective-C type parameter and type argument + // lists. RAngleLoc = Tok.getLocation(); - - // The source range of the '>>' or '>=' at the start of the token. - CharSourceRange ReplacementRange = - CharSourceRange::getCharRange(RAngleLoc, - Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(), - getLangOpts())); - - // A hint to put a space between the '>>'s. In order to make the hint as - // clear as possible, we include the characters either side of the space in - // the replacement, rather than just inserting a space at SecondCharLoc. - FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange, - ReplacementStr); - - // A hint to put another space after the token, if it would otherwise be - // lexed differently. - FixItHint Hint2; Token Next = NextToken(); - if ((RemainingToken == tok::greater || - RemainingToken == tok::greatergreater) && - Next.isOneOf(tok::greater, tok::greatergreater, - tok::greatergreatergreater, tok::equal, tok::greaterequal, - tok::greatergreaterequal, tok::equalequal) && - areTokensAdjacent(Tok, Next)) - Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " "); - - unsigned DiagId = diag::err_two_right_angle_brackets_need_space; - if (getLangOpts().CPlusPlus11 && - Tok.isOneOf(tok::greatergreater, tok::greatergreatergreater)) - DiagId = diag::warn_cxx98_compat_two_right_angle_brackets; - else if (Tok.is(tok::greaterequal)) - DiagId = diag::err_right_angle_bracket_equal_needs_space; - Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2; + if (!ObjCGenericList) { + // The source range of the '>>' or '>=' at the start of the token. + CharSourceRange ReplacementRange = + CharSourceRange::getCharRange(RAngleLoc, + Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(), + getLangOpts())); + + // A hint to put a space between the '>>'s. In order to make the hint as + // clear as possible, we include the characters either side of the space in + // the replacement, rather than just inserting a space at SecondCharLoc. + FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange, + ReplacementStr); + + // A hint to put another space after the token, if it would otherwise be + // lexed differently. + FixItHint Hint2; + if ((RemainingToken == tok::greater || + RemainingToken == tok::greatergreater) && + (Next.isOneOf(tok::greater, tok::greatergreater, + tok::greatergreatergreater, tok::equal, + tok::greaterequal, tok::greatergreaterequal, + tok::equalequal)) && + areTokensAdjacent(Tok, Next)) + Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " "); + + unsigned DiagId = diag::err_two_right_angle_brackets_need_space; + if (getLangOpts().CPlusPlus11 && + (Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater))) + DiagId = diag::warn_cxx98_compat_two_right_angle_brackets; + else if (Tok.is(tok::greaterequal)) + DiagId = diag::err_right_angle_bracket_equal_needs_space; + Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2; + } // Strip the initial '>' from the token. if (RemainingToken == tok::equal && Next.is(tok::equal) && @@ -895,7 +904,8 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, } } - return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken); + return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken, + /*ObjCGenericList=*/false); } /// \brief Replace the tokens that form a simple-template-id with an diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 368cb934bbaf..9d2a2b931e88 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -1281,6 +1281,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw__Nonnull: case tok::kw__Nullable: case tok::kw__Null_unspecified: + case tok::kw___kindof: return TPResult::True; // Borland @@ -1384,7 +1385,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case_typename: // In Objective-C, we might have a protocol-qualified type. if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { - // Tentatively parse the + // Tentatively parse the protocol qualifiers. TentativeParsingAction PA(*this); ConsumeToken(); // The type token diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index e32df95548d9..e76f767786f0 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1413,14 +1413,35 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, // It's not something we know about. Leave it unannotated. break; - case Sema::NC_Type: - Tok.setKind(tok::annot_typename); - setTypeAnnotation(Tok, Classification.getType()); - Tok.setAnnotationEndLoc(NameLoc); + case Sema::NC_Type: { + SourceLocation BeginLoc = NameLoc; if (SS.isNotEmpty()) - Tok.setLocation(SS.getBeginLoc()); + BeginLoc = SS.getBeginLoc(); + + /// An Objective-C object type followed by '<' is a specialization of + /// a parameterized class type or a protocol-qualified type. + ParsedType Ty = Classification.getType(); + if (getLangOpts().ObjC1 && NextToken().is(tok::less) && + (Ty.get()->isObjCObjectType() || + Ty.get()->isObjCObjectPointerType())) { + // Consume the name. + SourceLocation IdentifierLoc = ConsumeToken(); + SourceLocation NewEndLoc; + TypeResult NewType + = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty, + /*consumeLastToken=*/false, + NewEndLoc); + if (NewType.isUsable()) + Ty = NewType.get(); + } + + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Ty); + Tok.setAnnotationEndLoc(Tok.getLocation()); + Tok.setLocation(BeginLoc); PP.AnnotateCachedTokens(Tok); return ANK_Success; + } case Sema::NC_Expression: Tok.setKind(tok::annot_primary_expr); @@ -1627,13 +1648,33 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, // A FixIt was applied as a result of typo correction if (CorrectedII) Tok.setIdentifierInfo(CorrectedII); + + SourceLocation BeginLoc = Tok.getLocation(); + if (SS.isNotEmpty()) // it was a C++ qualified type name. + BeginLoc = SS.getBeginLoc(); + + /// An Objective-C object type followed by '<' is a specialization of + /// a parameterized class type or a protocol-qualified type. + if (getLangOpts().ObjC1 && NextToken().is(tok::less) && + (Ty.get()->isObjCObjectType() || + Ty.get()->isObjCObjectPointerType())) { + // Consume the name. + SourceLocation IdentifierLoc = ConsumeToken(); + SourceLocation NewEndLoc; + TypeResult NewType + = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty, + /*consumeLastToken=*/false, + NewEndLoc); + if (NewType.isUsable()) + Ty = NewType.get(); + } + // This is a typename. Replace the current token in-place with an // annotation type token. Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Ty); Tok.setAnnotationEndLoc(Tok.getLocation()); - if (SS.isNotEmpty()) // it was a C++ qualified type name. - Tok.setLocation(SS.getBeginLoc()); + Tok.setLocation(BeginLoc); // In case the tokens were cached, have Preprocessor replace // them with the annotation token. diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 69ae4f01dc7b..18e9a5911641 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -444,7 +444,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef, getAllocator(), + = Results[I].CreateCodeCompletionString(SemaRef, Context, + getAllocator(), CCTUInfo, includeBriefComments())) { OS << " : " << CCS->getAsString(); @@ -462,7 +463,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, case CodeCompletionResult::RK_Macro: { OS << Results[I].Macro->getName(); if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef, getAllocator(), + = Results[I].CreateCodeCompletionString(SemaRef, Context, + getAllocator(), CCTUInfo, includeBriefComments())) { OS << " : " << CCS->getAsString(); diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index d5c8871cac87..ea3872f42700 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -905,20 +905,6 @@ bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, return false; } -void DeclSpec::setProtocolQualifiers(Decl * const *Protos, - unsigned NP, - SourceLocation *ProtoLocs, - SourceLocation LAngleLoc) { - if (NP == 0) return; - Decl **ProtoQuals = new Decl*[NP]; - memcpy(ProtoQuals, Protos, sizeof(Decl*)*NP); - ProtocolQualifiers = ProtoQuals; - ProtocolLocs = new SourceLocation[NP]; - memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP); - NumProtocolQualifiers = NP; - ProtocolLAngleLoc = LAngleLoc; -} - void DeclSpec::SaveWrittenBuiltinSpecs() { writtenBS.Sign = getTypeSpecSign(); writtenBS.Width = getTypeSpecWidth(); diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index d9dc4df9f271..c0754ba7902a 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -975,7 +975,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, if (tcr != TC_NotApplicable) return tcr; - // C++0x [expr.static.cast]p3: + // C++11 [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2 // T2" if "cv2 T2" is reference-compatible with "cv1 T1". tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, @@ -1133,7 +1133,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, CastKind &Kind, CXXCastPath &BasePath, unsigned &msg) { - // C++0x [expr.static.cast]p3: + // C++11 [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to // cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". const RValueReferenceType *R = DestType->getAs<RValueReferenceType>(); @@ -1161,6 +1161,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, DerivedToBase, ObjCConversion, ObjCLifetimeConversion) < Sema::Ref_Compatible_With_Added_Qualification) { + if (CStyle) + return TC_NotApplicable; msg = diag::err_bad_lvalue_to_rvalue_cast; return TC_Failed; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index bdfff80c7f20..d9d26e2af602 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -6884,6 +6884,101 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, S.getFixItZeroLiteralForType(T, Loc)); } +static void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral); +static void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral); + +/// Check a single element within a collection literal against the +/// target element type. +static void checkObjCCollectionLiteralElement(Sema &S, + QualType TargetElementType, + Expr *Element, + unsigned ElementKind) { + // Skip a bitcast to 'id' or qualified 'id'. + if (auto ICE = dyn_cast<ImplicitCastExpr>(Element)) { + if (ICE->getCastKind() == CK_BitCast && + ICE->getSubExpr()->getType()->getAs<ObjCObjectPointerType>()) + Element = ICE->getSubExpr(); + } + + QualType ElementType = Element->getType(); + ExprResult ElementResult(Element); + if (ElementType->getAs<ObjCObjectPointerType>() && + S.CheckSingleAssignmentConstraints(TargetElementType, + ElementResult, + false, false) + != Sema::Compatible) { + S.Diag(Element->getLocStart(), + diag::warn_objc_collection_literal_element) + << ElementType << ElementKind << TargetElementType + << Element->getSourceRange(); + } + + if (auto ArrayLiteral = dyn_cast<ObjCArrayLiteral>(Element)) + checkObjCArrayLiteral(S, TargetElementType, ArrayLiteral); + else if (auto DictionaryLiteral = dyn_cast<ObjCDictionaryLiteral>(Element)) + checkObjCDictionaryLiteral(S, TargetElementType, DictionaryLiteral); +} + +/// Check an Objective-C array literal being converted to the given +/// target type. +static void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral) { + if (!S.NSArrayDecl) + return; + + const auto *TargetObjCPtr = TargetType->getAs<ObjCObjectPointerType>(); + if (!TargetObjCPtr) + return; + + if (TargetObjCPtr->isUnspecialized() || + TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() + != S.NSArrayDecl->getCanonicalDecl()) + return; + + auto TypeArgs = TargetObjCPtr->getTypeArgs(); + if (TypeArgs.size() != 1) + return; + + QualType TargetElementType = TypeArgs[0]; + for (unsigned I = 0, N = ArrayLiteral->getNumElements(); I != N; ++I) { + checkObjCCollectionLiteralElement(S, TargetElementType, + ArrayLiteral->getElement(I), + 0); + } +} + +/// Check an Objective-C dictionary literal being converted to the given +/// target type. +static void checkObjCDictionaryLiteral( + Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral) { + if (!S.NSDictionaryDecl) + return; + + const auto *TargetObjCPtr = TargetType->getAs<ObjCObjectPointerType>(); + if (!TargetObjCPtr) + return; + + if (TargetObjCPtr->isUnspecialized() || + TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() + != S.NSDictionaryDecl->getCanonicalDecl()) + return; + + auto TypeArgs = TargetObjCPtr->getTypeArgs(); + if (TypeArgs.size() != 2) + return; + + QualType TargetKeyType = TypeArgs[0]; + QualType TargetObjectType = TypeArgs[1]; + for (unsigned I = 0, N = DictionaryLiteral->getNumElements(); I != N; ++I) { + auto Element = DictionaryLiteral->getKeyValueElement(I); + checkObjCCollectionLiteralElement(S, TargetKeyType, Element.Key, 1); + checkObjCCollectionLiteralElement(S, TargetObjectType, Element.Value, 2); + } +} + void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, bool *ICContext = nullptr) { if (E->isTypeDependent() || E->isValueDependent()) return; @@ -6923,6 +7018,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } } + // Check implicit casts from Objective-C collection literals to specialized + // collection types, e.g., NSArray<NSString *> *. + if (auto *ArrayLiteral = dyn_cast<ObjCArrayLiteral>(E)) + checkObjCArrayLiteral(S, QualType(Target, 0), ArrayLiteral); + else if (auto *DictionaryLiteral = dyn_cast<ObjCDictionaryLiteral>(E)) + checkObjCDictionaryLiteral(S, QualType(Target, 0), DictionaryLiteral); + // Strip vector types. if (isa<VectorType>(Source)) { if (!isa<VectorType>(Target)) { diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index ff6a3eed8c25..86265275d05e 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2057,6 +2057,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, static void AddResultTypeChunk(ASTContext &Context, const PrintingPolicy &Policy, const NamedDecl *ND, + QualType BaseType, CodeCompletionBuilder &Result) { if (!ND) return; @@ -2070,16 +2071,28 @@ static void AddResultTypeChunk(ASTContext &Context, QualType T; if (const FunctionDecl *Function = ND->getAsFunction()) T = Function->getReturnType(); - else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) - T = Method->getReturnType(); - else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) + else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) { + if (!BaseType.isNull()) + T = Method->getSendResultType(BaseType); + else + T = Method->getReturnType(); + } else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext())); else if (isa<UnresolvedUsingValueDecl>(ND)) { /* Do nothing: ignore unresolved using declarations*/ + } else if (const ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(ND)) { + if (!BaseType.isNull()) + T = Ivar->getUsageType(BaseType); + else + T = Ivar->getType(); } else if (const ValueDecl *Value = dyn_cast<ValueDecl>(ND)) { T = Value->getType(); - } else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) - T = Property->getType(); + } else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) { + if (!BaseType.isNull()) + T = Property->getUsageType(BaseType); + else + T = Property->getType(); + } if (T.isNull() || Context.hasSameType(T, Context.DependentTy)) return; @@ -2140,7 +2153,8 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals, static std::string FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, bool SuppressName = false, - bool SuppressBlock = false) { + bool SuppressBlock = false, + Optional<ArrayRef<QualType>> ObjCSubsts = None) { bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { @@ -2152,6 +2166,9 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, Result = Param->getIdentifier()->getName(); QualType Type = Param->getType(); + if (ObjCSubsts) + Type = Type.substObjCTypeArgs(Param->getASTContext(), *ObjCSubsts, + ObjCSubstitutionContext::Parameter); if (ObjCMethodParam) { Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type); @@ -2187,6 +2204,11 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, TL = QualifiedTL.getUnqualifiedLoc(); continue; } + + if (AttributedTypeLoc AttrTL = TL.getAs<AttributedTypeLoc>()) { + TL = AttrTL.getModifiedLoc(); + continue; + } } // Try to get the function prototype behind the block pointer type, @@ -2226,6 +2248,10 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, // written in the source. std::string Result; QualType ResultType = Block.getTypePtr()->getReturnType(); + if (ObjCSubsts) + ResultType = ResultType.substObjCTypeArgs(Param->getASTContext(), + *ObjCSubsts, + ObjCSubstitutionContext::Result); if (!ResultType->isVoidType() || SuppressBlock) ResultType.getAsStringInternal(Result, Policy); @@ -2243,7 +2269,8 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, Params += ", "; Params += FormatFunctionParameter(Policy, Block.getParam(I), /*SuppressName=*/false, - /*SuppressBlock=*/true); + /*SuppressBlock=*/true, + ObjCSubsts); if (I == N - 1 && BlockProto.getTypePtr()->isVariadic()) Params += ", ..."; @@ -2537,11 +2564,12 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, } CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S, + const CodeCompletionContext &CCContext, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) { - return CreateCodeCompletionString(S.Context, S.PP, Allocator, CCTUInfo, - IncludeBriefComments); + return CreateCodeCompletionString(S.Context, S.PP, CCContext, Allocator, + CCTUInfo, IncludeBriefComments); } /// \brief If possible, create a new code completion string for the given @@ -2553,6 +2581,7 @@ CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S, CodeCompletionString * CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, Preprocessor &PP, + const CodeCompletionContext &CCContext, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) { @@ -2666,7 +2695,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, for (const auto *I : ND->specific_attrs<AnnotateAttr>()) Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation())); - AddResultTypeChunk(Ctx, Policy, ND, Result); + AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, @@ -2786,14 +2815,22 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, continue; std::string Arg; - - if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity) - Arg = FormatFunctionParameter(Policy, *P, true); + QualType ParamType = (*P)->getType(); + Optional<ArrayRef<QualType>> ObjCSubsts; + if (!CCContext.getBaseType().isNull()) + ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method); + + if (ParamType->isBlockPointerType() && !DeclaringEntity) + Arg = FormatFunctionParameter(Policy, *P, true, + /*SuppressBlock=*/false, + ObjCSubsts); else { - QualType Type = (*P)->getType(); + if (ObjCSubsts) + ParamType = ParamType.substObjCTypeArgs(Ctx, *ObjCSubsts, + ObjCSubstitutionContext::Parameter); Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier(), - Type); - Arg += Type.getAsString(Policy) + ")"; + ParamType); + Arg += ParamType.getAsString(Policy) + ")"; if (IdentifierInfo *II = (*P)->getIdentifier()) if (DeclaringEntity || AllParametersAreInformative) Arg += II->getName(); @@ -2930,7 +2967,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( if (auto RC = S.getASTContext().getRawCommentForAnyRedecl( FDecl->getParamDecl(CurrentArg))) Result.addBriefComment(RC->getBriefText(S.getASTContext())); - AddResultTypeChunk(S.Context, Policy, FDecl, Result); + AddResultTypeChunk(S.Context, Policy, FDecl, QualType(), Result); Result.AddTextChunk( Result.getAllocator().CopyString(FDecl->getNameAsString())); } else { @@ -3029,7 +3066,9 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) { case Decl::Import: return CXCursor_ModuleImportDecl; - + + case Decl::ObjCTypeParam: return CXCursor_TemplateTypeParameter; + default: if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { switch (TD->getTagKind()) { @@ -3520,7 +3559,8 @@ static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) { return Container; } -static void AddObjCProperties(ObjCContainerDecl *Container, +static void AddObjCProperties(const CodeCompletionContext &CCContext, + ObjCContainerDecl *Container, bool AllowCategories, bool AllowNullaryMethods, DeclContext *CurContext, @@ -3547,7 +3587,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container, if (AddedProperties.insert(Name).second) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - AddResultTypeChunk(Context, Policy, M, Builder); + AddResultTypeChunk(Context, Policy, M, CCContext.getBaseType(), + Builder); Builder.AddTypedTextChunk( Results.getAllocator().CopyString(Name->getName())); @@ -3562,32 +3603,32 @@ static void AddObjCProperties(ObjCContainerDecl *Container, // Add properties in referenced protocols. if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { for (auto *P : Protocol->protocols()) - AddObjCProperties(P, AllowCategories, AllowNullaryMethods, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){ if (AllowCategories) { // Look through categories. for (auto *Cat : IFace->known_categories()) - AddObjCProperties(Cat, AllowCategories, AllowNullaryMethods, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, Cat, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); } // Look through protocols. for (auto *I : IFace->all_referenced_protocols()) - AddObjCProperties(I, AllowCategories, AllowNullaryMethods, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, I, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); // Look in the superclass. if (IFace->getSuperClass()) - AddObjCProperties(IFace->getSuperClass(), AllowCategories, + AddObjCProperties(CCContext, IFace->getSuperClass(), AllowCategories, AllowNullaryMethods, CurContext, AddedProperties, Results); } else if (const ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { // Look through protocols. for (auto *P : Category->protocols()) - AddObjCProperties(P, AllowCategories, AllowNullaryMethods, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); } } @@ -3629,11 +3670,11 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, contextKind = CodeCompletionContext::CCC_DotMemberAccess; } } - + + CodeCompletionContext CCContext(contextKind, BaseType); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext(contextKind, - BaseType), + CCContext, &ResultBuilder::IsMember); Results.EnterNewScope(); if (const RecordType *Record = BaseType->getAs<RecordType>()) { @@ -3673,14 +3714,14 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, const ObjCObjectPointerType *ObjCPtr = BaseType->getAsObjCInterfacePointerType(); assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); - AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, + AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true, /*AllowNullaryMethods=*/true, CurContext, AddedProperties, Results); // Add properties from the protocols in a qualified interface. for (auto *I : ObjCPtr->quals()) - AddObjCProperties(I, true, /*AllowNullaryMethods=*/true, CurContext, - AddedProperties, Results); + AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true, + CurContext, AddedProperties, Results); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. @@ -4368,9 +4409,12 @@ void Sema::CodeCompleteOperatorName(Scope *S) { void Sema::CodeCompleteConstructorInitializer( Decl *ConstructorD, ArrayRef <CXXCtorInitializer *> Initializers) { - PrintingPolicy Policy = getCompletionPrintingPolicy(*this); - CXXConstructorDecl *Constructor - = static_cast<CXXConstructorDecl *>(ConstructorD); + if (!ConstructorD) + return; + + AdjustDeclIfTemplate(ConstructorD); + + CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ConstructorD); if (!Constructor) return; @@ -4394,6 +4438,7 @@ void Sema::CodeCompleteConstructorInitializer( // Add completions for base classes. CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); + PrintingPolicy Policy = getCompletionPrintingPolicy(*this); bool SawLastInitializer = Initializers.empty(); CXXRecordDecl *ClassDecl = Constructor->getParent(); for (const auto &Base : ClassDecl->bases()) { @@ -5334,7 +5379,8 @@ static ObjCMethodDecl *AddSuperSendCompletion( Results.getCodeCompletionTUInfo()); // Give this completion a return type. - AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod, + AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod, + Results.getCompletionContext().getBaseType(), Builder); // If we need the "super" keyword, add it (plus some spacing). @@ -6088,9 +6134,10 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, } void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { + CodeCompletionContext CCContext(CodeCompletionContext::CCC_Other); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext::CCC_Other); + CCContext); // Figure out where this @synthesize lives. ObjCContainerDecl *Container @@ -6111,11 +6158,12 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { Results.EnterNewScope(); if (ObjCImplementationDecl *ClassImpl = dyn_cast<ObjCImplementationDecl>(Container)) - AddObjCProperties(ClassImpl->getClassInterface(), false, + AddObjCProperties(CCContext, ClassImpl->getClassInterface(), false, /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); else - AddObjCProperties(cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(), + AddObjCProperties(CCContext, + cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(), false, /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); Results.ExitScope(); @@ -7032,7 +7080,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // If the result type was not already provided, add it to the // pattern as (type). if (ReturnType.isNull()) - AddObjCPassingTypeChunk(Method->getReturnType(), + AddObjCPassingTypeChunk(Method->getSendResultType() + .stripObjCKindOfType(Context), Method->getObjCDeclQualifier(), Context, Policy, Builder); @@ -7063,6 +7112,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, ParamType = (*P)->getType(); else ParamType = (*P)->getOriginalType(); + ParamType = ParamType.substObjCTypeArgs(Context, {}, + ObjCSubstitutionContext::Parameter); AddObjCPassingTypeChunk(ParamType, (*P)->getObjCDeclQualifier(), Context, Policy, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6508d6f04bb2..99d4a79c4669 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2577,6 +2577,48 @@ static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) { return false; } +template<typename T> static bool isExternC(T *D) { return D->isExternC(); } +static bool isExternC(VarTemplateDecl *) { return false; } + +/// \brief Check whether a redeclaration of an entity introduced by a +/// using-declaration is valid, given that we know it's not an overload +/// (nor a hidden tag declaration). +template<typename ExpectedDecl> +static bool checkUsingShadowRedecl(Sema &S, UsingShadowDecl *OldS, + ExpectedDecl *New) { + // C++11 [basic.scope.declarative]p4: + // Given a set of declarations in a single declarative region, each of + // which specifies the same unqualified name, + // -- they shall all refer to the same entity, or all refer to functions + // and function templates; or + // -- exactly one declaration shall declare a class name or enumeration + // name that is not a typedef name and the other declarations shall all + // refer to the same variable or enumerator, or all refer to functions + // and function templates; in this case the class name or enumeration + // name is hidden (3.3.10). + + // C++11 [namespace.udecl]p14: + // If a function declaration in namespace scope or block scope has the + // same name and the same parameter-type-list as a function introduced + // by a using-declaration, and the declarations do not declare the same + // function, the program is ill-formed. + + auto *Old = dyn_cast<ExpectedDecl>(OldS->getTargetDecl()); + if (Old && + !Old->getDeclContext()->getRedeclContext()->Equals( + New->getDeclContext()->getRedeclContext()) && + !(isExternC(Old) && isExternC(New))) + Old = nullptr; + + if (!Old) { + S.Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); + S.Diag(OldS->getTargetDecl()->getLocation(), diag::note_using_decl_target); + S.Diag(OldS->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; + return true; + } + return false; +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -2603,28 +2645,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, return true; } - // C++11 [namespace.udecl]p14: - // If a function declaration in namespace scope or block scope has the - // same name and the same parameter-type-list as a function introduced - // by a using-declaration, and the declarations do not declare the same - // function, the program is ill-formed. - // Check whether the two declarations might declare the same function. - Old = dyn_cast<FunctionDecl>(Shadow->getTargetDecl()); - if (Old && - !Old->getDeclContext()->getRedeclContext()->Equals( - New->getDeclContext()->getRedeclContext()) && - !(Old->isExternC() && New->isExternC())) - Old = nullptr; - - if (!Old) { - Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); - Diag(Shadow->getTargetDecl()->getLocation(), - diag::note_using_decl_target); - Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; + if (checkUsingShadowRedecl<FunctionDecl>(*this, Shadow, New)) return true; - } - OldD = Old; + OldD = Old = cast<FunctionDecl>(Shadow->getTargetDecl()); } else { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); @@ -3246,9 +3270,16 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, // // Neither C nor C++ requires a diagnostic for this, but we should still try // to diagnose it. - Diag(New->getLocation(), diag::err_redefinition_different_type) - << New->getDeclName() << New->getType() << Old->getType(); - Diag(Old->getLocation(), diag::note_previous_definition); + Diag(New->getLocation(), New->isThisDeclarationADefinition() + ? diag::err_redefinition_different_type + : diag::err_redeclaration_different_type) + << New->getDeclName() << New->getType() << Old->getType(); + + diag::kind PrevDiag; + SourceLocation OldLocation; + std::tie(PrevDiag, OldLocation) = + getNoteDiagForInvalidRedeclaration(Old, New); + Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } @@ -3309,8 +3340,19 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (NewTemplate) { OldTemplate = dyn_cast<VarTemplateDecl>(Previous.getFoundDecl()); Old = OldTemplate ? OldTemplate->getTemplatedDecl() : nullptr; - } else + + if (auto *Shadow = + dyn_cast<UsingShadowDecl>(Previous.getRepresentativeDecl())) + if (checkUsingShadowRedecl<VarTemplateDecl>(*this, Shadow, NewTemplate)) + return New->setInvalidDecl(); + } else { Old = dyn_cast<VarDecl>(Previous.getFoundDecl()); + + if (auto *Shadow = + dyn_cast<UsingShadowDecl>(Previous.getRepresentativeDecl())) + if (checkUsingShadowRedecl<VarDecl>(*this, Shadow, New)) + return New->setInvalidDecl(); + } } if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) @@ -4742,15 +4784,16 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, } } - if (DiagnoseClassNameShadow(DC, NameInfo)) + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType R = TInfo->getType(); + + if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo)) // If this is a typedef, we'll end up spewing multiple diagnostics. - // Just return early; it's safer. + // Just return early; it's safer. If this is a function, let the + // "constructor cannot have a return type" diagnostic handle it. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) return nullptr; - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); - QualType R = TInfo->getType(); - if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_DeclarationType)) D.setInvalidType(); @@ -9785,6 +9828,16 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { FinalizeVarWithDestructor(var, recordType); } +/// \brief Determines if a variable's alignment is dependent. +static bool hasDependentAlignment(VarDecl *VD) { + if (VD->getType()->isDependentType()) + return true; + for (auto *I : VD->specific_attrs<AlignedAttr>()) + if (I->isAlignmentDependent()) + return true; + return false; +} + /// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform /// any semantic actions necessary after any initializer has been attached. void @@ -9798,6 +9851,22 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { checkAttributesAfterMerging(*this, *VD); + // Perform TLS alignment check here after attributes attached to the variable + // which may affect the alignment have been processed. Only perform the check + // if the target has a maximum TLS alignment (zero means no constraints). + if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) { + // Protect the check so that it's not performed on dependent types and + // dependent alignments (we can't determine the alignment in that case). + if (VD->getTLSKind() && !hasDependentAlignment(VD)) { + CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign); + if (Context.getDeclAlign(VD) > MaxAlignChars) { + Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) + << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD + << (unsigned)MaxAlignChars.getQuantity(); + } + } + } + // Static locals inherit dll attributes from their function. if (VD->isStaticLocal()) { if (FunctionDecl *FD = @@ -11258,7 +11327,7 @@ static bool isClassCompatTagKind(TagTypeKind Tag) bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, - const IdentifierInfo &Name) { + const IdentifierInfo *Name) { // C++ [dcl.type.elab]p3: // The class-key or enum keyword present in the // elaborated-type-specifier shall agree in kind with the @@ -11287,7 +11356,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // In a template instantiation, do not offer fix-its for tag mismatches // since they usually mess up the template instead of fixing the problem. Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name << getRedeclDiagFromTagKind(OldTag); return true; } @@ -11306,7 +11375,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, if (!previousMismatch) { previousMismatch = true; Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) - << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name << getRedeclDiagFromTagKind(I->getTagKind()); } Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) @@ -11328,7 +11397,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, } Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name << getRedeclDiagFromTagKind(OldTag); Diag(Redecl->getLocation(), diag::note_previous_use); @@ -11388,6 +11457,27 @@ static FixItHint createFriendTagNNSFixIt(Sema &SemaRef, NamedDecl *ND, Scope *S, return FixItHint::CreateInsertion(NameLoc, Insertion); } +/// \brief Determine whether a tag originally declared in context \p OldDC can +/// be redeclared with an unqualfied name in \p NewDC (assuming name lookup +/// found a declaration in \p OldDC as a previous decl, perhaps through a +/// using-declaration). +static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC, + DeclContext *NewDC) { + OldDC = OldDC->getRedeclContext(); + NewDC = NewDC->getRedeclContext(); + + if (OldDC->Equals(NewDC)) + return true; + + // In MSVC mode, we allow a redeclaration if the contexts are related (either + // encloses the other). + if (S.getLangOpts().MSVCCompat && + (OldDC->Encloses(NewDC) || NewDC->Encloses(OldDC))) + return true; + + return false; +} + /// \brief This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a @@ -11559,6 +11649,14 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, goto CreateNewDecl; } } else if (Name) { + // C++14 [class.mem]p14: + // If T is the name of a class, then each of the following shall have a + // name different from T: + // -- every member of class T that is itself a type + if (TUK != TUK_Reference && TUK != TUK_Friend && + DiagnoseClassNameShadow(SearchDC, DeclarationNameInfo(Name, NameLoc))) + return nullptr; + // If this is a named struct, check to see if there was a previous forward // declaration or definition. // FIXME: We're looking into outer scopes here, even when we @@ -11724,8 +11822,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (!Previous.empty()) { NamedDecl *PrevDecl = Previous.getFoundDecl(); - NamedDecl *DirectPrevDecl = - getLangOpts().MSVCCompat ? *Previous.begin() : PrevDecl; + NamedDecl *DirectPrevDecl = Previous.getRepresentativeDecl(); // It's okay to have a tag decl in the same scope as a typedef // which hides a tag decl in the same scope. Finding this @@ -11752,6 +11849,26 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + // If this is a redeclaration of a using shadow declaration, it must + // declare a tag in the same context. In MSVC mode, we allow a + // redefinition if either context is within the other. + if (auto *Shadow = dyn_cast<UsingShadowDecl>(DirectPrevDecl)) { + auto *OldTag = dyn_cast<TagDecl>(PrevDecl); + if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend && + isDeclInScope(Shadow, SearchDC, S, isExplicitSpecialization) && + !(OldTag && isAcceptableTagRedeclContext( + *this, OldTag->getDeclContext(), SearchDC))) { + Diag(KWLoc, diag::err_using_decl_conflict_reverse); + Diag(Shadow->getTargetDecl()->getLocation(), + diag::note_using_decl_target); + Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) + << 0; + // Recover by ignoring the old declaration. + Previous.clear(); + goto CreateNewDecl; + } + } + if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or @@ -11763,7 +11880,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // struct or something similar. if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, TUK == TUK_Definition, KWLoc, - *Name)) { + Name)) { bool SafeToContinue = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum); @@ -11940,7 +12057,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Invalid = true; // Otherwise, only diagnose if the declaration is in scope. - } else if (!isDeclInScope(PrevDecl, SearchDC, S, + } else if (!isDeclInScope(DirectPrevDecl, SearchDC, S, SS.isNotEmpty() || isExplicitSpecialization)) { // do nothing @@ -13619,12 +13736,9 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, // different from T: // - every enumerator of every member of class T that is an unscoped // enumerated type - if (CXXRecordDecl *Record - = dyn_cast<CXXRecordDecl>( - TheEnumDecl->getDeclContext()->getRedeclContext())) - if (!TheEnumDecl->isScoped() && - Record->getIdentifier() && Record->getIdentifier() == Id) - Diag(IdLoc, diag::err_member_name_of_class) << Id; + if (!TheEnumDecl->isScoped()) + DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(), + DeclarationNameInfo(Id, IdLoc)); EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index b8d083068593..191dbd05c9bd 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2985,11 +2985,27 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, // specifier shall have no effect // C11 6.7.5p6: // An alignment specification of zero has no effect. - if (!(TmpAttr.isAlignas() && !Alignment) && - !llvm::isPowerOf2_64(Alignment.getZExtValue())) { - Diag(AttrLoc, diag::err_alignment_not_power_of_two) - << E->getSourceRange(); - return; + if (!(TmpAttr.isAlignas() && !Alignment)) { + if(!llvm::isPowerOf2_64(Alignment.getZExtValue())) { + Diag(AttrLoc, diag::err_alignment_not_power_of_two) + << E->getSourceRange(); + return; + } + if (Context.getTargetInfo().isTLSSupported()) { + if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) { + if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->getTLSKind()) { + CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign); + if (Alignment.getSExtValue() > MaxAlignChars.getQuantity()) { + Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) + << (unsigned)Alignment.getZExtValue() << VD + << (unsigned)MaxAlignChars.getQuantity(); + return; + } + } + } + } + } } // Alignment calculations can wrap around if it's greater than 2**28. diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index d0b299877e0f..f42c4b7546ce 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -20,12 +20,15 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "TypeLocBuilder.h" using namespace clang; @@ -461,10 +464,424 @@ static void diagnoseUseOfProtocols(Sema &TheSema, } } +void Sema:: +ActOnSuperClassOfClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, + ObjCInterfaceDecl *IDecl, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange) { + // Check if a different kind of symbol declared in this scope. + NamedDecl *PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, + LookupOrdinaryName); + + if (!PrevDecl) { + // Try to correct for a typo in the superclass name without correcting + // to the class we're defining. + if (TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(SuperName, SuperLoc), + LookupOrdinaryName, TUScope, + NULL, llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), + CTK_ErrorRecovery)) { + diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) + << SuperName << ClassName); + PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); + } + } + + if (declaresSameEntity(PrevDecl, IDecl)) { + Diag(SuperLoc, diag::err_recursive_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + IDecl->setEndOfDefinitionLoc(ClassLoc); + } else { + ObjCInterfaceDecl *SuperClassDecl = + dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + QualType SuperClassType; + + // Diagnose classes that inherit from deprecated classes. + if (SuperClassDecl) { + (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); + SuperClassType = Context.getObjCInterfaceType(SuperClassDecl); + } + + if (PrevDecl && SuperClassDecl == 0) { + // The previous declaration was not a class decl. Check if we have a + // typedef. If we do, get the underlying class type. + if (const TypedefNameDecl *TDecl = + dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { + QualType T = TDecl->getUnderlyingType(); + if (T->isObjCObjectType()) { + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { + SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); + SuperClassType = Context.getTypeDeclType(TDecl); + + // This handles the following case: + // @interface NewI @end + // typedef NewI DeprI __attribute__((deprecated("blah"))) + // @interface SI : DeprI /* warn here */ @end + (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc); + } + } + } + + // This handles the following case: + // + // typedef int SuperClass; + // @interface MyClass : SuperClass {} @end + // + if (!SuperClassDecl) { + Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + } + } + + if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { + if (!SuperClassDecl) + Diag(SuperLoc, diag::err_undef_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + else if (RequireCompleteType(SuperLoc, + SuperClassType, + diag::err_forward_superclass, + SuperClassDecl->getDeclName(), + ClassName, + SourceRange(AtInterfaceLoc, ClassLoc))) { + SuperClassDecl = 0; + SuperClassType = QualType(); + } + } + + if (SuperClassType.isNull()) { + assert(!SuperClassDecl && "Failed to set SuperClassType?"); + return; + } + + // Handle type arguments on the superclass. + TypeSourceInfo *SuperClassTInfo = nullptr; + if (!SuperTypeArgs.empty()) { + TypeResult fullSuperClassType = actOnObjCTypeArgsAndProtocolQualifiers( + S, + SuperLoc, + CreateParsedType(SuperClassType, + nullptr), + SuperTypeArgsRange.getBegin(), + SuperTypeArgs, + SuperTypeArgsRange.getEnd(), + SourceLocation(), + { }, + { }, + SourceLocation()); + if (!fullSuperClassType.isUsable()) + return; + + SuperClassType = GetTypeFromParser(fullSuperClassType.get(), + &SuperClassTInfo); + } + + if (!SuperClassTInfo) { + SuperClassTInfo = Context.getTrivialTypeSourceInfo(SuperClassType, + SuperLoc); + } + + IDecl->setSuperClass(SuperClassTInfo); + IDecl->setEndOfDefinitionLoc(SuperClassTInfo->getTypeLoc().getLocEnd()); + } +} + +DeclResult Sema::actOnObjCTypeParam(Scope *S, + ObjCTypeParamVariance variance, + SourceLocation varianceLoc, + unsigned index, + IdentifierInfo *paramName, + SourceLocation paramLoc, + SourceLocation colonLoc, + ParsedType parsedTypeBound) { + // If there was an explicitly-provided type bound, check it. + TypeSourceInfo *typeBoundInfo = nullptr; + if (parsedTypeBound) { + // The type bound can be any Objective-C pointer type. + QualType typeBound = GetTypeFromParser(parsedTypeBound, &typeBoundInfo); + if (typeBound->isObjCObjectPointerType()) { + // okay + } else if (typeBound->isObjCObjectType()) { + // The user forgot the * on an Objective-C pointer type, e.g., + // "T : NSView". + SourceLocation starLoc = PP.getLocForEndOfToken( + typeBoundInfo->getTypeLoc().getEndLoc()); + Diag(typeBoundInfo->getTypeLoc().getBeginLoc(), + diag::err_objc_type_param_bound_missing_pointer) + << typeBound << paramName + << FixItHint::CreateInsertion(starLoc, " *"); + + // Create a new type location builder so we can update the type + // location information we have. + TypeLocBuilder builder; + builder.pushFullCopy(typeBoundInfo->getTypeLoc()); + + // Create the Objective-C pointer type. + typeBound = Context.getObjCObjectPointerType(typeBound); + ObjCObjectPointerTypeLoc newT + = builder.push<ObjCObjectPointerTypeLoc>(typeBound); + newT.setStarLoc(starLoc); + + // Form the new type source information. + typeBoundInfo = builder.getTypeSourceInfo(Context, typeBound); + } else { + // Not a valid type bound. + Diag(typeBoundInfo->getTypeLoc().getBeginLoc(), + diag::err_objc_type_param_bound_nonobject) + << typeBound << paramName; + + // Forget the bound; we'll default to id later. + typeBoundInfo = nullptr; + } + + // Type bounds cannot have explicit nullability. + if (typeBoundInfo) { + // Type arguments cannot explicitly specify nullability. + if (auto nullability = AttributedType::stripOuterNullability(typeBound)) { + // Look at the type location information to find the nullability + // specifier so we can zap it. + SourceLocation nullabilityLoc + = typeBoundInfo->getTypeLoc().findNullabilityLoc(); + SourceLocation diagLoc + = nullabilityLoc.isValid()? nullabilityLoc + : typeBoundInfo->getTypeLoc().getLocStart(); + Diag(diagLoc, diag::err_type_param_bound_explicit_nullability) + << paramName << typeBoundInfo->getType() + << FixItHint::CreateRemoval(nullabilityLoc); + } + } + } + + // If there was no explicit type bound (or we removed it due to an error), + // use 'id' instead. + if (!typeBoundInfo) { + colonLoc = SourceLocation(); + typeBoundInfo = Context.getTrivialTypeSourceInfo(Context.getObjCIdType()); + } + + // Create the type parameter. + return ObjCTypeParamDecl::Create(Context, CurContext, variance, varianceLoc, + index, paramLoc, paramName, colonLoc, + typeBoundInfo); +} + +ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S, + SourceLocation lAngleLoc, + ArrayRef<Decl *> typeParamsIn, + SourceLocation rAngleLoc) { + // We know that the array only contains Objective-C type parameters. + ArrayRef<ObjCTypeParamDecl *> + typeParams( + reinterpret_cast<ObjCTypeParamDecl * const *>(typeParamsIn.data()), + typeParamsIn.size()); + + // Diagnose redeclarations of type parameters. + // We do this now because Objective-C type parameters aren't pushed into + // scope until later (after the instance variable block), but we want the + // diagnostics to occur right after we parse the type parameter list. + llvm::SmallDenseMap<IdentifierInfo *, ObjCTypeParamDecl *> knownParams; + for (auto typeParam : typeParams) { + auto known = knownParams.find(typeParam->getIdentifier()); + if (known != knownParams.end()) { + Diag(typeParam->getLocation(), diag::err_objc_type_param_redecl) + << typeParam->getIdentifier() + << SourceRange(known->second->getLocation()); + + typeParam->setInvalidDecl(); + } else { + knownParams.insert(std::make_pair(typeParam->getIdentifier(), typeParam)); + + // Push the type parameter into scope. + PushOnScopeChains(typeParam, S, /*AddToContext=*/false); + } + } + + // Create the parameter list. + return ObjCTypeParamList::create(Context, lAngleLoc, typeParams, rAngleLoc); +} + +void Sema::popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList) { + for (auto typeParam : *typeParamList) { + if (!typeParam->isInvalidDecl()) { + S->RemoveDecl(typeParam); + IdResolver.RemoveDecl(typeParam); + } + } +} + +namespace { + /// The context in which an Objective-C type parameter list occurs, for use + /// in diagnostics. + enum class TypeParamListContext { + ForwardDeclaration, + Definition, + Category, + Extension + }; +} + +/// Check consistency between two Objective-C type parameter lists, e.g., +/// between a category/extension and an \@interface or between an \@class and an +/// \@interface. +static bool checkTypeParamListConsistency(Sema &S, + ObjCTypeParamList *prevTypeParams, + ObjCTypeParamList *newTypeParams, + TypeParamListContext newContext) { + // If the sizes don't match, complain about that. + if (prevTypeParams->size() != newTypeParams->size()) { + SourceLocation diagLoc; + if (newTypeParams->size() > prevTypeParams->size()) { + diagLoc = newTypeParams->begin()[prevTypeParams->size()]->getLocation(); + } else { + diagLoc = S.PP.getLocForEndOfToken(newTypeParams->back()->getLocEnd()); + } + + S.Diag(diagLoc, diag::err_objc_type_param_arity_mismatch) + << static_cast<unsigned>(newContext) + << (newTypeParams->size() > prevTypeParams->size()) + << prevTypeParams->size() + << newTypeParams->size(); + + return true; + } + + // Match up the type parameters. + for (unsigned i = 0, n = prevTypeParams->size(); i != n; ++i) { + ObjCTypeParamDecl *prevTypeParam = prevTypeParams->begin()[i]; + ObjCTypeParamDecl *newTypeParam = newTypeParams->begin()[i]; + + // Check for consistency of the variance. + if (newTypeParam->getVariance() != prevTypeParam->getVariance()) { + if (newTypeParam->getVariance() == ObjCTypeParamVariance::Invariant && + newContext != TypeParamListContext::Definition) { + // When the new type parameter is invariant and is not part + // of the definition, just propagate the variance. + newTypeParam->setVariance(prevTypeParam->getVariance()); + } else if (prevTypeParam->getVariance() + == ObjCTypeParamVariance::Invariant && + !(isa<ObjCInterfaceDecl>(prevTypeParam->getDeclContext()) && + cast<ObjCInterfaceDecl>(prevTypeParam->getDeclContext()) + ->getDefinition() == prevTypeParam->getDeclContext())) { + // When the old parameter is invariant and was not part of the + // definition, just ignore the difference because it doesn't + // matter. + } else { + { + // Diagnose the conflict and update the second declaration. + SourceLocation diagLoc = newTypeParam->getVarianceLoc(); + if (diagLoc.isInvalid()) + diagLoc = newTypeParam->getLocStart(); + + auto diag = S.Diag(diagLoc, + diag::err_objc_type_param_variance_conflict) + << static_cast<unsigned>(newTypeParam->getVariance()) + << newTypeParam->getDeclName() + << static_cast<unsigned>(prevTypeParam->getVariance()) + << prevTypeParam->getDeclName(); + switch (prevTypeParam->getVariance()) { + case ObjCTypeParamVariance::Invariant: + diag << FixItHint::CreateRemoval(newTypeParam->getVarianceLoc()); + break; + + case ObjCTypeParamVariance::Covariant: + case ObjCTypeParamVariance::Contravariant: { + StringRef newVarianceStr + = prevTypeParam->getVariance() == ObjCTypeParamVariance::Covariant + ? "__covariant" + : "__contravariant"; + if (newTypeParam->getVariance() + == ObjCTypeParamVariance::Invariant) { + diag << FixItHint::CreateInsertion(newTypeParam->getLocStart(), + (newVarianceStr + " ").str()); + } else { + diag << FixItHint::CreateReplacement(newTypeParam->getVarianceLoc(), + newVarianceStr); + } + } + } + } + + S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here) + << prevTypeParam->getDeclName(); + + // Override the variance. + newTypeParam->setVariance(prevTypeParam->getVariance()); + } + } + + // If the bound types match, there's nothing to do. + if (S.Context.hasSameType(prevTypeParam->getUnderlyingType(), + newTypeParam->getUnderlyingType())) + continue; + + // If the new type parameter's bound was explicit, complain about it being + // different from the original. + if (newTypeParam->hasExplicitBound()) { + SourceRange newBoundRange = newTypeParam->getTypeSourceInfo() + ->getTypeLoc().getSourceRange(); + S.Diag(newBoundRange.getBegin(), diag::err_objc_type_param_bound_conflict) + << newTypeParam->getUnderlyingType() + << newTypeParam->getDeclName() + << prevTypeParam->hasExplicitBound() + << prevTypeParam->getUnderlyingType() + << (newTypeParam->getDeclName() == prevTypeParam->getDeclName()) + << prevTypeParam->getDeclName() + << FixItHint::CreateReplacement( + newBoundRange, + prevTypeParam->getUnderlyingType().getAsString( + S.Context.getPrintingPolicy())); + + S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here) + << prevTypeParam->getDeclName(); + + // Override the new type parameter's bound type with the previous type, + // so that it's consistent. + newTypeParam->setTypeSourceInfo( + S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType())); + continue; + } + + // The new type parameter got the implicit bound of 'id'. That's okay for + // categories and extensions (overwrite it later), but not for forward + // declarations and @interfaces, because those must be standalone. + if (newContext == TypeParamListContext::ForwardDeclaration || + newContext == TypeParamListContext::Definition) { + // Diagnose this problem for forward declarations and definitions. + SourceLocation insertionLoc + = S.PP.getLocForEndOfToken(newTypeParam->getLocation()); + std::string newCode + = " : " + prevTypeParam->getUnderlyingType().getAsString( + S.Context.getPrintingPolicy()); + S.Diag(newTypeParam->getLocation(), + diag::err_objc_type_param_bound_missing) + << prevTypeParam->getUnderlyingType() + << newTypeParam->getDeclName() + << (newContext == TypeParamListContext::ForwardDeclaration) + << FixItHint::CreateInsertion(insertionLoc, newCode); + + S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here) + << prevTypeParam->getDeclName(); + } + + // Update the new type parameter's bound to match the previous one. + newTypeParam->setTypeSourceInfo( + S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType())); + } + + return false; +} + Decl *Sema:: -ActOnStartClassInterface(SourceLocation AtInterfaceLoc, +ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, + ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { @@ -498,10 +915,50 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, ClassName = PrevIDecl->getIdentifier(); } + // If there was a forward declaration with type parameters, check + // for consistency. + if (PrevIDecl) { + if (ObjCTypeParamList *prevTypeParamList = PrevIDecl->getTypeParamList()) { + if (typeParamList) { + // Both have type parameter lists; check for consistency. + if (checkTypeParamListConsistency(*this, prevTypeParamList, + typeParamList, + TypeParamListContext::Definition)) { + typeParamList = nullptr; + } + } else { + Diag(ClassLoc, diag::err_objc_parameterized_forward_class_first) + << ClassName; + Diag(prevTypeParamList->getLAngleLoc(), diag::note_previous_decl) + << ClassName; + + // Clone the type parameter list. + SmallVector<ObjCTypeParamDecl *, 4> clonedTypeParams; + for (auto typeParam : *prevTypeParamList) { + clonedTypeParams.push_back( + ObjCTypeParamDecl::Create( + Context, + CurContext, + typeParam->getVariance(), + SourceLocation(), + typeParam->getIndex(), + SourceLocation(), + typeParam->getIdentifier(), + SourceLocation(), + Context.getTrivialTypeSourceInfo(typeParam->getUnderlyingType()))); + } + + typeParamList = ObjCTypeParamList::create(Context, + SourceLocation(), + clonedTypeParams, + SourceLocation()); + } + } + } + ObjCInterfaceDecl *IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName, - PrevIDecl, ClassLoc); - + typeParamList, PrevIDecl, ClassLoc); if (PrevIDecl) { // Class already seen. Was it a definition? if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) { @@ -522,84 +979,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IDecl->startDefinition(); if (SuperName) { - // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, - LookupOrdinaryName); - - if (!PrevDecl) { - // Try to correct for a typo in the superclass name without correcting - // to the class we're defining. - if (TypoCorrection Corrected = - CorrectTypo(DeclarationNameInfo(SuperName, SuperLoc), - LookupOrdinaryName, TUScope, nullptr, - llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), - CTK_ErrorRecovery)) { - diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) - << SuperName << ClassName); - PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); - } - } - - if (declaresSameEntity(PrevDecl, IDecl)) { - Diag(SuperLoc, diag::err_recursive_superclass) - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - IDecl->setEndOfDefinitionLoc(ClassLoc); - } else { - ObjCInterfaceDecl *SuperClassDecl = - dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); - - // Diagnose availability in the context of the @interface. - ContextRAII SavedContext(*this, IDecl); - // Diagnose classes that inherit from deprecated classes. - if (SuperClassDecl) - (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); - - if (PrevDecl && !SuperClassDecl) { - // The previous declaration was not a class decl. Check if we have a - // typedef. If we do, get the underlying class type. - if (const TypedefNameDecl *TDecl = - dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { - QualType T = TDecl->getUnderlyingType(); - if (T->isObjCObjectType()) { - if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { - SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); - // This handles the following case: - // @interface NewI @end - // typedef NewI DeprI __attribute__((deprecated("blah"))) - // @interface SI : DeprI /* warn here */ @end - (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc); - } - } - } + // Diagnose availability in the context of the @interface. + ContextRAII SavedContext(*this, IDecl); - // This handles the following case: - // - // typedef int SuperClass; - // @interface MyClass : SuperClass {} @end - // - if (!SuperClassDecl) { - Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; - Diag(PrevDecl->getLocation(), diag::note_previous_definition); - } - } - - if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { - if (!SuperClassDecl) - Diag(SuperLoc, diag::err_undef_superclass) - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - else if (RequireCompleteType(SuperLoc, - Context.getObjCInterfaceType(SuperClassDecl), - diag::err_forward_superclass, - SuperClassDecl->getDeclName(), - ClassName, - SourceRange(AtInterfaceLoc, ClassLoc))) { - SuperClassDecl = nullptr; - } - } - IDecl->setSuperClass(SuperClassDecl); - IDecl->setSuperClassLoc(SuperLoc); - IDecl->setEndOfDefinitionLoc(SuperLoc); - } + ActOnSuperClassOfClassInterface(S, AtInterfaceLoc, IDecl, + ClassName, ClassLoc, + SuperName, SuperLoc, SuperTypeArgs, + SuperTypeArgsRange); } else { // we have a root class. IDecl->setEndOfDefinitionLoc(ClassLoc); } @@ -846,6 +1232,400 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, } } +namespace { +// Callback to only accept typo corrections that are either +// Objective-C protocols or valid Objective-C type arguments. +class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback { + ASTContext &Context; + Sema::LookupNameKind LookupKind; + public: + ObjCTypeArgOrProtocolValidatorCCC(ASTContext &context, + Sema::LookupNameKind lookupKind) + : Context(context), LookupKind(lookupKind) { } + + bool ValidateCandidate(const TypoCorrection &candidate) override { + // If we're allowed to find protocols and we have a protocol, accept it. + if (LookupKind != Sema::LookupOrdinaryName) { + if (candidate.getCorrectionDeclAs<ObjCProtocolDecl>()) + return true; + } + + // If we're allowed to find type names and we have one, accept it. + if (LookupKind != Sema::LookupObjCProtocolName) { + // If we have a type declaration, we might accept this result. + if (auto typeDecl = candidate.getCorrectionDeclAs<TypeDecl>()) { + // If we found a tag declaration outside of C++, skip it. This + // can happy because we look for any name when there is no + // bias to protocol or type names. + if (isa<RecordDecl>(typeDecl) && !Context.getLangOpts().CPlusPlus) + return false; + + // Make sure the type is something we would accept as a type + // argument. + auto type = Context.getTypeDeclType(typeDecl); + if (type->isObjCObjectPointerType() || + type->isBlockPointerType() || + type->isDependentType() || + type->isObjCObjectType()) + return true; + + return false; + } + + // If we have an Objective-C class type, accept it; there will + // be another fix to add the '*'. + if (candidate.getCorrectionDeclAs<ObjCInterfaceDecl>()) + return true; + + return false; + } + + return false; + } +}; +} // end anonymous namespace + +void Sema::actOnObjCTypeArgsOrProtocolQualifiers( + Scope *S, + ParsedType baseType, + SourceLocation lAngleLoc, + ArrayRef<IdentifierInfo *> identifiers, + ArrayRef<SourceLocation> identifierLocs, + SourceLocation rAngleLoc, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SourceLocation &protocolRAngleLoc, + bool warnOnIncompleteProtocols) { + // Local function that updates the declaration specifiers with + // protocol information. + unsigned numProtocolsResolved = 0; + auto resolvedAsProtocols = [&] { + assert(numProtocolsResolved == identifiers.size() && "Unresolved protocols"); + + // Determine whether the base type is a parameterized class, in + // which case we want to warn about typos such as + // "NSArray<NSObject>" (that should be NSArray<NSObject *>). + ObjCInterfaceDecl *baseClass = nullptr; + QualType base = GetTypeFromParser(baseType, nullptr); + bool allAreTypeNames = false; + SourceLocation firstClassNameLoc; + if (!base.isNull()) { + if (const auto *objcObjectType = base->getAs<ObjCObjectType>()) { + baseClass = objcObjectType->getInterface(); + if (baseClass) { + if (auto typeParams = baseClass->getTypeParamList()) { + if (typeParams->size() == numProtocolsResolved) { + // Note that we should be looking for type names, too. + allAreTypeNames = true; + } + } + } + } + } + + for (unsigned i = 0, n = protocols.size(); i != n; ++i) { + ObjCProtocolDecl *&proto + = reinterpret_cast<ObjCProtocolDecl *&>(protocols[i]); + // For an objc container, delay protocol reference checking until after we + // can set the objc decl as the availability context, otherwise check now. + if (!warnOnIncompleteProtocols) { + (void)DiagnoseUseOfDecl(proto, identifierLocs[i]); + } + + // If this is a forward protocol declaration, get its definition. + if (!proto->isThisDeclarationADefinition() && proto->getDefinition()) + proto = proto->getDefinition(); + + // If this is a forward declaration and we are supposed to warn in this + // case, do it. + // FIXME: Recover nicely in the hidden case. + ObjCProtocolDecl *forwardDecl = nullptr; + if (warnOnIncompleteProtocols && + NestedProtocolHasNoDefinition(proto, forwardDecl)) { + Diag(identifierLocs[i], diag::warn_undef_protocolref) + << proto->getDeclName(); + Diag(forwardDecl->getLocation(), diag::note_protocol_decl_undefined) + << forwardDecl; + } + + // If everything this far has been a type name (and we care + // about such things), check whether this name refers to a type + // as well. + if (allAreTypeNames) { + if (auto *decl = LookupSingleName(S, identifiers[i], identifierLocs[i], + LookupOrdinaryName)) { + if (isa<ObjCInterfaceDecl>(decl)) { + if (firstClassNameLoc.isInvalid()) + firstClassNameLoc = identifierLocs[i]; + } else if (!isa<TypeDecl>(decl)) { + // Not a type. + allAreTypeNames = false; + } + } else { + allAreTypeNames = false; + } + } + } + + // All of the protocols listed also have type names, and at least + // one is an Objective-C class name. Check whether all of the + // protocol conformances are declared by the base class itself, in + // which case we warn. + if (allAreTypeNames && firstClassNameLoc.isValid()) { + llvm::SmallPtrSet<ObjCProtocolDecl*, 8> knownProtocols; + Context.CollectInheritedProtocols(baseClass, knownProtocols); + bool allProtocolsDeclared = true; + for (auto proto : protocols) { + if (knownProtocols.count(static_cast<ObjCProtocolDecl *>(proto)) == 0) { + allProtocolsDeclared = false; + break; + } + } + + if (allProtocolsDeclared) { + Diag(firstClassNameLoc, diag::warn_objc_redundant_qualified_class_type) + << baseClass->getDeclName() << SourceRange(lAngleLoc, rAngleLoc) + << FixItHint::CreateInsertion( + PP.getLocForEndOfToken(firstClassNameLoc), " *"); + } + } + + protocolLAngleLoc = lAngleLoc; + protocolRAngleLoc = rAngleLoc; + assert(protocols.size() == identifierLocs.size()); + }; + + // Attempt to resolve all of the identifiers as protocols. + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + ObjCProtocolDecl *proto = LookupProtocol(identifiers[i], identifierLocs[i]); + protocols.push_back(proto); + if (proto) + ++numProtocolsResolved; + } + + // If all of the names were protocols, these were protocol qualifiers. + if (numProtocolsResolved == identifiers.size()) + return resolvedAsProtocols(); + + // Attempt to resolve all of the identifiers as type names or + // Objective-C class names. The latter is technically ill-formed, + // but is probably something like \c NSArray<NSView *> missing the + // \c*. + typedef llvm::PointerUnion<TypeDecl *, ObjCInterfaceDecl *> TypeOrClassDecl; + SmallVector<TypeOrClassDecl, 4> typeDecls; + unsigned numTypeDeclsResolved = 0; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + NamedDecl *decl = LookupSingleName(S, identifiers[i], identifierLocs[i], + LookupOrdinaryName); + if (!decl) { + typeDecls.push_back(TypeOrClassDecl()); + continue; + } + + if (auto typeDecl = dyn_cast<TypeDecl>(decl)) { + typeDecls.push_back(typeDecl); + ++numTypeDeclsResolved; + continue; + } + + if (auto objcClass = dyn_cast<ObjCInterfaceDecl>(decl)) { + typeDecls.push_back(objcClass); + ++numTypeDeclsResolved; + continue; + } + + typeDecls.push_back(TypeOrClassDecl()); + } + + AttributeFactory attrFactory; + + // Local function that forms a reference to the given type or + // Objective-C class declaration. + auto resolveTypeReference = [&](TypeOrClassDecl typeDecl, SourceLocation loc) + -> TypeResult { + // Form declaration specifiers. They simply refer to the type. + DeclSpec DS(attrFactory); + const char* prevSpec; // unused + unsigned diagID; // unused + QualType type; + if (auto *actualTypeDecl = typeDecl.dyn_cast<TypeDecl *>()) + type = Context.getTypeDeclType(actualTypeDecl); + else + type = Context.getObjCInterfaceType(typeDecl.get<ObjCInterfaceDecl *>()); + TypeSourceInfo *parsedTSInfo = Context.getTrivialTypeSourceInfo(type, loc); + ParsedType parsedType = CreateParsedType(type, parsedTSInfo); + DS.SetTypeSpecType(DeclSpec::TST_typename, loc, prevSpec, diagID, + parsedType, Context.getPrintingPolicy()); + // Use the identifier location for the type source range. + DS.SetRangeStart(loc); + DS.SetRangeEnd(loc); + + // Form the declarator. + Declarator D(DS, Declarator::TypeNameContext); + + // If we have a typedef of an Objective-C class type that is missing a '*', + // add the '*'. + if (type->getAs<ObjCInterfaceType>()) { + SourceLocation starLoc = PP.getLocForEndOfToken(loc); + ParsedAttributes parsedAttrs(attrFactory); + D.AddTypeInfo(DeclaratorChunk::getPointer(/*typeQuals=*/0, starLoc, + SourceLocation(), + SourceLocation(), + SourceLocation(), + SourceLocation()), + parsedAttrs, + starLoc); + + // Diagnose the missing '*'. + Diag(loc, diag::err_objc_type_arg_missing_star) + << type + << FixItHint::CreateInsertion(starLoc, " *"); + } + + // Convert this to a type. + return ActOnTypeName(S, D); + }; + + // Local function that updates the declaration specifiers with + // type argument information. + auto resolvedAsTypeDecls = [&] { + // We did not resolve these as protocols. + protocols.clear(); + + assert(numTypeDeclsResolved == identifiers.size() && "Unresolved type decl"); + // Map type declarations to type arguments. + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + // Map type reference to a type. + TypeResult type = resolveTypeReference(typeDecls[i], identifierLocs[i]); + if (!type.isUsable()) { + typeArgs.clear(); + return; + } + + typeArgs.push_back(type.get()); + } + + typeArgsLAngleLoc = lAngleLoc; + typeArgsRAngleLoc = rAngleLoc; + }; + + // If all of the identifiers can be resolved as type names or + // Objective-C class names, we have type arguments. + if (numTypeDeclsResolved == identifiers.size()) + return resolvedAsTypeDecls(); + + // Error recovery: some names weren't found, or we have a mix of + // type and protocol names. Go resolve all of the unresolved names + // and complain if we can't find a consistent answer. + LookupNameKind lookupKind = LookupAnyName; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + // If we already have a protocol or type. Check whether it is the + // right thing. + if (protocols[i] || typeDecls[i]) { + // If we haven't figured out whether we want types or protocols + // yet, try to figure it out from this name. + if (lookupKind == LookupAnyName) { + // If this name refers to both a protocol and a type (e.g., \c + // NSObject), don't conclude anything yet. + if (protocols[i] && typeDecls[i]) + continue; + + // Otherwise, let this name decide whether we'll be correcting + // toward types or protocols. + lookupKind = protocols[i] ? LookupObjCProtocolName + : LookupOrdinaryName; + continue; + } + + // If we want protocols and we have a protocol, there's nothing + // more to do. + if (lookupKind == LookupObjCProtocolName && protocols[i]) + continue; + + // If we want types and we have a type declaration, there's + // nothing more to do. + if (lookupKind == LookupOrdinaryName && typeDecls[i]) + continue; + + // We have a conflict: some names refer to protocols and others + // refer to types. + Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols) + << (protocols[i] != nullptr) + << identifiers[i] + << identifiers[0] + << SourceRange(identifierLocs[0]); + + protocols.clear(); + typeArgs.clear(); + return; + } + + // Perform typo correction on the name. + TypoCorrection corrected = CorrectTypo( + DeclarationNameInfo(identifiers[i], identifierLocs[i]), lookupKind, S, + nullptr, + llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(Context, + lookupKind), + CTK_ErrorRecovery); + if (corrected) { + // Did we find a protocol? + if (auto proto = corrected.getCorrectionDeclAs<ObjCProtocolDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_undeclared_protocol_suggest) + << identifiers[i]); + lookupKind = LookupObjCProtocolName; + protocols[i] = proto; + ++numProtocolsResolved; + continue; + } + + // Did we find a type? + if (auto typeDecl = corrected.getCorrectionDeclAs<TypeDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_unknown_typename_suggest) + << identifiers[i]); + lookupKind = LookupOrdinaryName; + typeDecls[i] = typeDecl; + ++numTypeDeclsResolved; + continue; + } + + // Did we find an Objective-C class? + if (auto objcClass = corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_unknown_type_or_class_name_suggest) + << identifiers[i] << true); + lookupKind = LookupOrdinaryName; + typeDecls[i] = objcClass; + ++numTypeDeclsResolved; + continue; + } + } + + // We couldn't find anything. + Diag(identifierLocs[i], + (lookupKind == LookupAnyName ? diag::err_objc_type_arg_missing + : lookupKind == LookupObjCProtocolName ? diag::err_undeclared_protocol + : diag::err_unknown_typename)) + << identifiers[i]; + protocols.clear(); + typeArgs.clear(); + return; + } + + // If all of the names were (corrected to) protocols, these were + // protocol qualifiers. + if (numProtocolsResolved == identifiers.size()) + return resolvedAsProtocols(); + + // Otherwise, all of the names were (corrected to) types. + assert(numTypeDeclsResolved == identifiers.size() && "Not all types?"); + return resolvedAsTypeDecls(); +} + /// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of /// a class method in its extension. /// @@ -906,6 +1686,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, Decl *Sema:: ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, + ObjCTypeParamList *typeParamList, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl * const *ProtoRefs, @@ -925,7 +1706,8 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, // the enclosing method declarations. We mark the decl invalid // to make it clear that this isn't a valid AST. CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, - ClassLoc, CategoryLoc, CategoryName,IDecl); + ClassLoc, CategoryLoc, CategoryName, + IDecl, typeParamList); CDecl->setInvalidDecl(); CurContext->addDecl(CDecl); @@ -951,8 +1733,28 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, } } + // If we have a type parameter list, check it. + if (typeParamList) { + if (auto prevTypeParamList = IDecl->getTypeParamList()) { + if (checkTypeParamListConsistency(*this, prevTypeParamList, typeParamList, + CategoryName + ? TypeParamListContext::Category + : TypeParamListContext::Extension)) + typeParamList = nullptr; + } else { + Diag(typeParamList->getLAngleLoc(), + diag::err_objc_parameterized_category_nonclass) + << (CategoryName != nullptr) + << ClassName + << typeParamList->getSourceRange(); + + typeParamList = nullptr; + } + } + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, - ClassLoc, CategoryLoc, CategoryName, IDecl); + ClassLoc, CategoryLoc, CategoryName, IDecl, + typeParamList); // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); @@ -987,7 +1789,8 @@ Decl *Sema::ActOnStartCategoryImplementation( // Create and install one. CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, AtCatImplLoc, ClassLoc, CatLoc, - CatName, IDecl); + CatName, IDecl, + /*typeParamList=*/nullptr); CatIDecl->setImplicit(); } } @@ -1101,12 +1904,14 @@ Decl *Sema::ActOnStartClassImplementation( // FIXME: Do we support attributes on the @implementation? If so we should // copy them over. IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc, - ClassName, /*PrevDecl=*/nullptr, ClassLoc, + ClassName, /*typeParamList=*/nullptr, + /*PrevDecl=*/nullptr, ClassLoc, true); IDecl->startDefinition(); if (SDecl) { - IDecl->setSuperClass(SDecl); - IDecl->setSuperClassLoc(SuperClassLoc); + IDecl->setSuperClass(Context.getTrivialTypeSourceInfo( + Context.getObjCInterfaceType(SDecl), + SuperClassLoc)); IDecl->setEndOfDefinitionLoc(SuperClassLoc); } else { IDecl->setEndOfDefinitionLoc(ClassLoc); @@ -2083,6 +2888,7 @@ Sema::DeclGroupPtrTy Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, + ArrayRef<ObjCTypeParamList *> TypeParamLists, unsigned NumElts) { SmallVector<Decl *, 8> DeclsInGroup; for (unsigned i = 0; i != NumElts; ++i) { @@ -2137,9 +2943,33 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, ClassName = PrevIDecl->getIdentifier(); } + // If this forward declaration has type parameters, compare them with the + // type parameters of the previous declaration. + ObjCTypeParamList *TypeParams = TypeParamLists[i]; + if (PrevIDecl && TypeParams) { + if (ObjCTypeParamList *PrevTypeParams = PrevIDecl->getTypeParamList()) { + // Check for consistency with the previous declaration. + if (checkTypeParamListConsistency( + *this, PrevTypeParams, TypeParams, + TypeParamListContext::ForwardDeclaration)) { + TypeParams = nullptr; + } + } else if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) { + // The @interface does not have type parameters. Complain. + Diag(IdentLocs[i], diag::err_objc_parameterized_forward_class) + << ClassName + << TypeParams->getSourceRange(); + Diag(Def->getLocation(), diag::note_defined_here) + << ClassName; + + TypeParams = nullptr; + } + } + ObjCInterfaceDecl *IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc, - ClassName, PrevIDecl, IdentLocs[i]); + ClassName, TypeParams, PrevIDecl, + IdentLocs[i]); IDecl->setAtEndRange(IdentLocs[i]); PushOnScopeChains(IDecl, TUScope); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 2e3e63e00a32..094187025df0 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -397,7 +397,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // - both are dynamic-exception-specifications that have the same set of // adjusted types. // - // C++0x [except.spec]p12: An exception-specifcation is non-throwing if it is + // C++0x [except.spec]p12: An exception-specification is non-throwing if it is // of the form throw(), noexcept, or noexcept(constant-expression) where the // constant-expression yields true. // diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index c023c8523a39..1ae983cad227 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2466,8 +2466,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); ObjCIvarRefExpr *Result = new (Context) - ObjCIvarRefExpr(IV, IV->getType(), Loc, IV->getLocation(), - SelfExpr.get(), true, true); + ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, + IV->getLocation(), SelfExpr.get(), true, true); if (getLangOpts().ObjCAutoRefCount) { if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { @@ -5185,17 +5185,17 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, } /// Do an explicit extend of the given block pointer if we're in ARC. -static void maybeExtendBlockObject(Sema &S, ExprResult &E) { +void Sema::maybeExtendBlockObject(ExprResult &E) { assert(E.get()->getType()->isBlockPointerType()); assert(E.get()->isRValue()); // Only do this in an r-value context. - if (!S.getLangOpts().ObjCAutoRefCount) return; + if (!getLangOpts().ObjCAutoRefCount) return; - E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), + E = ImplicitCastExpr::Create(Context, E.get()->getType(), CK_ARCExtendBlockObject, E.get(), /*base path*/ nullptr, VK_RValue); - S.ExprNeedsCleanups = true; + ExprNeedsCleanups = true; } /// Prepare a conversion of the given expression to an ObjC object @@ -5205,7 +5205,7 @@ CastKind Sema::PrepareCastToObjCObjectPointer(ExprResult &E) { if (type->isObjCObjectPointerType()) { return CK_BitCast; } else if (type->isBlockPointerType()) { - maybeExtendBlockObject(*this, E); + maybeExtendBlockObject(E); return CK_BlockPointerToObjCPointerCast; } else { assert(type->isPointerType()); @@ -5247,7 +5247,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { return CK_BitCast; if (SrcKind == Type::STK_CPointer) return CK_CPointerToObjCPointerCast; - maybeExtendBlockObject(*this, Src); + maybeExtendBlockObject(Src); return CK_BlockPointerToObjCPointerCast; case Type::STK_Bool: return CK_PointerToBoolean; @@ -5826,36 +5826,6 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, return ResultTy; } -/// \brief Returns true if QT is quelified-id and implements 'NSObject' and/or -/// 'NSCopying' protocols (and nothing else); or QT is an NSObject and optionally -/// implements 'NSObject' and/or NSCopying' protocols (and nothing else). -static bool isObjCPtrBlockCompatible(Sema &S, ASTContext &C, QualType QT) { - if (QT->isObjCIdType()) - return true; - - const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>(); - if (!OPT) - return false; - - if (ObjCInterfaceDecl *ID = OPT->getInterfaceDecl()) - if (ID->getIdentifier() != &C.Idents.get("NSObject")) - return false; - - ObjCProtocolDecl* PNSCopying = - S.LookupProtocol(&C.Idents.get("NSCopying"), SourceLocation()); - ObjCProtocolDecl* PNSObject = - S.LookupProtocol(&C.Idents.get("NSObject"), SourceLocation()); - - for (auto *Proto : OPT->quals()) { - if ((PNSCopying && declaresSameEntity(Proto, PNSCopying)) || - (PNSObject && declaresSameEntity(Proto, PNSObject))) - ; - else - return false; - } - return true; -} - /// \brief Return the resulting type when the operands are both block pointers. static QualType checkConditionalBlockPointerCompatibility(Sema &S, ExprResult &LHS, @@ -6303,7 +6273,10 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. // It could return the composite type. - if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { + if (!(compositeType = + Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) { + // Nothing more to do. + } else if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy; } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy; @@ -6317,10 +6290,7 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, compositeType = Context.getObjCIdType(); } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { compositeType = Context.getObjCIdType(); - } else if (!(compositeType = - Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) - ; - else { + } else { Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); @@ -7008,9 +6978,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, } // Only under strict condition T^ is compatible with an Objective-C pointer. - if (RHSType->isBlockPointerType() && - isObjCPtrBlockCompatible(*this, Context, LHSType)) { - maybeExtendBlockObject(*this, RHS); + if (RHSType->isBlockPointerType() && + LHSType->isBlockCompatibleObjCPointerType(Context)) { + maybeExtendBlockObject(RHS); Kind = CK_BlockPointerToObjCPointerCast; return Compatible; } @@ -7937,9 +7907,19 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, // representable in the result type, so never warn for those. llvm::APSInt Left; if (LHS.get()->isValueDependent() || - !LHS.get()->isIntegerConstantExpr(Left, S.Context) || - LHSType->hasUnsignedIntegerRepresentation()) + LHSType->hasUnsignedIntegerRepresentation() || + !LHS.get()->EvaluateAsInt(Left, S.Context)) return; + + // If LHS does not have a signed type and non-negative value + // then, the behavior is undefined. Warn about it. + if (Left.isNegative()) { + S.DiagRuntimeBehavior(Loc, LHS.get(), + S.PDiag(diag::warn_shift_lhs_negative) + << LHS.get()->getSourceRange()); + return; + } + llvm::APInt ResultBits = static_cast<llvm::APInt&>(Right) + Left.getMinSignedBits(); if (LeftBits.uge(ResultBits)) @@ -8209,9 +8189,6 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) { // Get the LHS object's interface type. QualType InterfaceType = Type->getPointeeType(); - if (const ObjCObjectType *iQFaceTy = - InterfaceType->getAsObjCQualifiedInterfaceType()) - InterfaceType = iQFaceTy->getBaseType(); // If the RHS isn't an Objective-C object, bail out. if (!RHS->getType()->isObjCObjectPointerType()) @@ -12556,6 +12533,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, // By default, capture variables by reference. bool ByRef = true; // Using an LValue reference type is consistent with Lambdas (see below). + if (S.getLangOpts().OpenMP && S.IsOpenMPCapturedVar(Var)) + DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = S.Context.getLValueReferenceType(DeclRefType); Expr *CopyExpr = nullptr; if (BuildAndDiagnose) { @@ -12789,6 +12768,7 @@ bool Sema::tryCaptureVariable( if (RSI->CapRegionKind == CR_OpenMP) { if (isOpenMPPrivateVar(Var, OpenMPLevel)) { Nested = true; + DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = Context.getLValueReferenceType(DeclRefType); break; } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index e421349338b1..a9f1919e18a8 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -1378,7 +1378,8 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, } ObjCIvarRefExpr *Result = new (S.Context) ObjCIvarRefExpr( - IV, IV->getType(), MemberLoc, OpLoc, BaseExpr.get(), IsArrow); + IV, IV->getUsageType(BaseType), MemberLoc, OpLoc, BaseExpr.get(), + IsArrow); if (S.getLangOpts().ObjCAutoRefCount) { if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index c52b6f55a957..6cd062621951 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -133,7 +133,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){ ObjCInterfaceDecl::Create (Context, Context.getTranslationUnitDecl(), SourceLocation(), NSIdent, - nullptr, SourceLocation()); + nullptr, nullptr, SourceLocation()); Ty = Context.getObjCInterfaceType(NSStringIDecl); Context.setObjCNSStringType(Ty); } @@ -208,7 +208,8 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, S.NSNumberDecl = ObjCInterfaceDecl::Create(CX, CX.getTranslationUnitDecl(), SourceLocation(), NSNumberId, - nullptr, SourceLocation()); + nullptr, nullptr, + SourceLocation()); } else { // Otherwise, require a declaration of NSNumber. S.Diag(Loc, diag::err_undeclared_nsnumber); @@ -475,7 +476,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { NSStringDecl = ObjCInterfaceDecl::Create(Context, TU, SourceLocation(), NSStringId, - nullptr, SourceLocation()); + nullptr, nullptr, + SourceLocation()); } else { Diag(SR.getBegin(), diag::err_undeclared_nsstring); return ExprError(); @@ -591,7 +593,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { DeclContext *TU = Context.getTranslationUnitDecl(); NSValueDecl = ObjCInterfaceDecl::Create(Context, TU, SourceLocation(), NSValueId, - nullptr, SourceLocation()); + nullptr, nullptr, + SourceLocation()); } else { // Otherwise, require a declaration of NSValue. Diag(SR.getBegin(), diag::err_undeclared_nsvalue); @@ -755,7 +758,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { Context.getTranslationUnitDecl(), SourceLocation(), NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray), - nullptr, SourceLocation()); + nullptr, nullptr, SourceLocation()); if (!NSArrayDecl) { Diag(SR.getBegin(), diag::err_undeclared_nsarray); @@ -870,7 +873,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, Context.getTranslationUnitDecl(), SourceLocation(), NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary), - nullptr, SourceLocation()); + nullptr, nullptr, SourceLocation()); if (!NSDictionaryDecl) { Diag(SR.getBegin(), diag::err_undeclared_nsdictionary); @@ -956,8 +959,11 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) { ObjCProtocolDecl *PQ[] = {NSCopyingPDecl}; QIDNSCopying = - Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**) PQ,1); + Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, + llvm::makeArrayRef( + (ObjCProtocolDecl**) PQ, + 1), + false); QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying); } } @@ -1276,7 +1282,7 @@ static QualType getBaseMessageSendResultType(Sema &S, bool isSuperMessage) { assert(Method && "Must have a method"); if (!Method->hasRelatedResultType()) - return Method->getSendResultType(); + return Method->getSendResultType(ReceiverType); ASTContext &Context = S.Context; @@ -1284,7 +1290,8 @@ static QualType getBaseMessageSendResultType(Sema &S, // result type to the returned result. auto transferNullability = [&](QualType type) -> QualType { // If the method's result type has nullability, extract it. - if (auto nullability = Method->getSendResultType()->getNullability(Context)){ + if (auto nullability = Method->getSendResultType(ReceiverType) + ->getNullability(Context)){ // Strip off any outer nullability sugar from the provided type. (void)AttributedType::stripOuterNullability(type); @@ -1303,7 +1310,8 @@ static QualType getBaseMessageSendResultType(Sema &S, // was a class message send, T is the declared return type of the method // found if (Method->isInstanceMethod() && isClassMessage) - return stripObjCInstanceType(Context, Method->getSendResultType()); + return stripObjCInstanceType(Context, + Method->getSendResultType(ReceiverType)); // - if the receiver is super, T is a pointer to the class of the // enclosing method definition @@ -1317,14 +1325,14 @@ static QualType getBaseMessageSendResultType(Sema &S, } // - if the receiver is the name of a class U, T is a pointer to U - if (ReceiverType->getAs<ObjCInterfaceType>() || - ReceiverType->isObjCQualifiedInterfaceType()) + if (ReceiverType->getAsObjCInterfaceType()) return transferNullability(Context.getObjCObjectPointerType(ReceiverType)); // - if the receiver is of type Class or qualified Class type, // T is the declared return type of the method. if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) - return stripObjCInstanceType(Context, Method->getSendResultType()); + return stripObjCInstanceType(Context, + Method->getSendResultType(ReceiverType)); // - if the receiver is id, qualified id, Class, or qualified Class, T // is the receiver type, otherwise @@ -1587,6 +1595,10 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, return false; } + // Compute the set of type arguments to be substituted into each parameter + // type. + Optional<ArrayRef<QualType>> typeArgs + = ReceiverType->getObjCSubstitutions(Method->getDeclContext()); bool IsError = false; for (unsigned i = 0; i < NumNamedArgs; i++) { // We can't do any type-checking on a type-dependent argument. @@ -1620,18 +1632,37 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, continue; } + QualType origParamType = param->getType(); + QualType paramType = param->getType(); + if (typeArgs) + paramType = paramType.substObjCTypeArgs( + Context, + *typeArgs, + ObjCSubstitutionContext::Parameter); + if (RequireCompleteType(argExpr->getSourceRange().getBegin(), - param->getType(), + paramType, diag::err_call_incomplete_argument, argExpr)) return true; - InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, - param); + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, param, paramType); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr); if (ArgE.isInvalid()) IsError = true; - else + else { Args[i] = ArgE.getAs<Expr>(); + + // If we are type-erasing a block to a block-compatible + // Objective-C pointer type, we may need to extend the lifetime + // of the block object. + if (typeArgs && Args[i]->isRValue() && paramType->isBlockPointerType() && + origParamType->isBlockCompatibleObjCPointerType(Context)) { + ExprResult arg = Args[i]; + maybeExtendBlockObject(arg); + Args[i] = arg.get(); + } + } } // Promote additional arguments to variadic methods. @@ -1899,27 +1930,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, receiverNameLoc); - bool IsSuper = false; + QualType SuperType; if (!IFace) { // If the "receiver" is 'super' in a method, handle it as an expression-like // property reference. if (receiverNamePtr->isStr("super")) { - IsSuper = true; - if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) { - if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) { + if (auto classDecl = CurMethod->getClassInterface()) { + SuperType = QualType(classDecl->getSuperClassType(), 0); if (CurMethod->isInstanceMethod()) { - ObjCInterfaceDecl *Super = Class->getSuperClass(); - if (!Super) { + if (SuperType.isNull()) { // The current class does not have a superclass. Diag(receiverNameLoc, diag::error_root_class_cannot_use_super) - << Class->getIdentifier(); + << CurMethod->getClassInterface()->getIdentifier(); return ExprError(); } - QualType T = Context.getObjCInterfaceType(Super); - T = Context.getObjCObjectPointerType(T); + QualType T = Context.getObjCObjectPointerType(SuperType); - return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), + return HandleExprPropertyRefExpr(T->castAs<ObjCObjectPointerType>(), /*BaseExpr*/nullptr, SourceLocation()/*OpLoc*/, &propertyName, @@ -1929,7 +1957,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, // Otherwise, if this is a class method, try dispatching to our // superclass. - IFace = Class->getSuperClass(); + IFace = CurMethod->getClassInterface()->getSuperClass(); } } } @@ -1959,7 +1987,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, // Look for the matching setter, in case it is needed. Selector SetterSel = SelectorTable::constructSetterSelector(PP.getIdentifierTable(), - PP.getSelectorTable(), + PP.getSelectorTable(), &propertyName); ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); @@ -1976,11 +2004,11 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, return ExprError(); if (Getter || Setter) { - if (IsSuper) + if (!SuperType.isNull()) return new (Context) ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, propertyNameLoc, receiverNameLoc, - Context.getObjCInterfaceType(IFace)); + SuperType); return new (Context) ObjCPropertyRefExpr( Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, @@ -2127,8 +2155,8 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, return ExprError(); } - ObjCInterfaceDecl *Super = Class->getSuperClass(); - if (!Super) { + QualType SuperTy(Class->getSuperClassType(), 0); + if (SuperTy.isNull()) { // The current class does not have a superclass. Diag(SuperLoc, diag::error_root_class_cannot_use_super) << Class->getIdentifier(); @@ -2143,7 +2171,6 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, if (Method->isInstanceMethod()) { // Since we are in an instance method, this is an instance // message to the superclass instance. - QualType SuperTy = Context.getObjCInterfaceType(Super); SuperTy = Context.getObjCObjectPointerType(SuperTy); return BuildInstanceMessage(nullptr, SuperTy, SuperLoc, Sel, /*Method=*/nullptr, @@ -2153,7 +2180,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, // Since we are in a class method, this is a class message to // the superclass. return BuildClassMessage(/*ReceiverTypeInfo=*/nullptr, - Context.getObjCInterfaceType(Super), + SuperTy, SuperLoc, Sel, /*Method=*/nullptr, LBracLoc, SelectorLocs, RBracLoc, Args); } @@ -2594,35 +2621,41 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // of the more detailed type-checking on the receiver. if (!Method) { - // Handle messages to id. - bool receiverIsId = ReceiverType->isObjCIdType(); - if (receiverIsId || ReceiverType->isBlockPointerType() || + // Handle messages to id and __kindof types (where we use the + // global method pool). + // FIXME: The type bound is currently ignored by lookup in the + // global pool. + const ObjCObjectType *typeBound = nullptr; + bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context, + typeBound); + if (receiverIsIdLike || ReceiverType->isBlockPointerType() || (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), - receiverIsId); + receiverIsIdLike); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc,RBracLoc), - receiverIsId); + receiverIsIdLike); if (Method) { if (ObjCMethodDecl *BestMethod = SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) Method = BestMethod; if (!AreMultipleMethodsInGlobalPool(Sel, Method, SourceRange(LBracLoc, RBracLoc), - receiverIsId)) { + receiverIsIdLike)) { DiagnoseUseOfDecl(Method, SelLoc); } } - } else if (ReceiverType->isObjCClassType() || + } else if (ReceiverType->isObjCClassOrClassKindOfType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. // We allow sending a message to a qualified Class ("Class<foo>"), which // is ok as long as one of the protocols implements the selector (if not, // warn). - if (const ObjCObjectPointerType *QClassTy - = ReceiverType->getAsObjCQualifiedClassType()) { + if (!ReceiverType->isObjCClassOrClassKindOfType()) { + const ObjCObjectPointerType *QClassTy + = ReceiverType->getAsObjCQualifiedClassType(); // Search protocols for class methods. Method = LookupMethodInQualifiedType(Sel, QClassTy, false); if (!Method) { diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 0f88abcdf9ea..f139c83c734b 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1157,7 +1157,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, CK_LValueToRValue, SelfExpr, nullptr, VK_RValue); Expr *IvarRefExpr = - new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + new (Context) ObjCIvarRefExpr(Ivar, + Ivar->getUsageType(SelfDecl->getType()), + PropertyDiagLoc, Ivar->getLocation(), LoadSelfExpr, true, true); ExprResult Res = PerformCopyInitialization( @@ -1207,7 +1209,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, CK_LValueToRValue, SelfExpr, nullptr, VK_RValue); Expr *lhs = - new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + new (Context) ObjCIvarRefExpr(Ivar, + Ivar->getUsageType(SelfDecl->getType()), + PropertyDiagLoc, Ivar->getLocation(), LoadSelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 867cb9f3c830..4030d9e66e02 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -21,6 +21,7 @@ #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -472,7 +473,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables appearing in threadprivate directives are threadprivate. - if (D->getTLSKind() != VarDecl::TLS_None || + if ((D->getTLSKind() != VarDecl::TLS_None && + !(D->hasAttr<OMPThreadPrivateDeclAttr>() && + SemaRef.getLangOpts().OpenMPUseTLS && + SemaRef.getASTContext().getTargetInfo().isTLSSupported())) || (D->getStorageClass() == SC_Register && D->hasAttr<AsmLabelAttr>() && !D->isLocalVarDecl())) { addDSA(D, buildDeclRefExpr(SemaRef, D, D->getType().getNonReferenceType(), @@ -959,8 +963,12 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { continue; } - // Check if this is a TLS variable. - if (VD->getTLSKind() != VarDecl::TLS_None || + // Check if this is a TLS variable. If TLS is not being supported, produce + // the corresponding diagnostic. + if ((VD->getTLSKind() != VarDecl::TLS_None && + !(VD->hasAttr<OMPThreadPrivateDeclAttr>() && + getLangOpts().OpenMPUseTLS && + getASTContext().getTargetInfo().isTLSSupported())) || (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())) { Diag(ILoc, diag::err_omp_var_thread_local) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index a0fdcd78e596..31f581dc15b6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2152,23 +2152,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, FromObjCPtr->getPointeeType())) return false; - // Check for compatible - // Objective C++: We're able to convert between "id" or "Class" and a - // pointer to any interface (in both directions). - if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) { - ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); - return true; - } - // Conversions with Objective-C's id<...>. - if ((FromObjCPtr->isObjCQualifiedIdType() || - ToObjCPtr->isObjCQualifiedIdType()) && - Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType, - /*compare=*/false)) { - ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); - return true; - } - // Objective C++: We're able to convert from a pointer to an - // interface to a pointer to a different interface. + // Conversion between Objective-C pointers. if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) { const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType(); const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType(); diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index 3e465af9632c..fec97488f531 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -689,15 +689,7 @@ ExprResult ObjCPropertyOpBuilder::buildGet() { if (SyntacticRefExpr) SyntacticRefExpr->setIsMessagingGetter(); - QualType receiverType; - if (RefExpr->isClassReceiver()) { - receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); - } else if (RefExpr->isSuperReceiver()) { - receiverType = RefExpr->getSuperReceiverType(); - } else { - assert(InstanceReceiver); - receiverType = InstanceReceiver->getType(); - } + QualType receiverType = RefExpr->getReceiverType(S.Context); if (!Getter->isImplicit()) S.DiagnoseUseOfDecl(Getter, GenericLoc, nullptr, true); // Build a message-send. @@ -730,21 +722,17 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, if (SyntacticRefExpr) SyntacticRefExpr->setIsMessagingSetter(); - QualType receiverType; - if (RefExpr->isClassReceiver()) { - receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); - } else if (RefExpr->isSuperReceiver()) { - receiverType = RefExpr->getSuperReceiverType(); - } else { - assert(InstanceReceiver); - receiverType = InstanceReceiver->getType(); - } + QualType receiverType = RefExpr->getReceiverType(S.Context); // Use assignment constraints when possible; they give us better // diagnostics. "When possible" basically means anything except a // C++ class type. if (!S.getLangOpts().CPlusPlus || !op->getType()->isRecordType()) { - QualType paramType = (*Setter->param_begin())->getType(); + QualType paramType = (*Setter->param_begin())->getType() + .substObjCMemberType( + receiverType, + Setter->getDeclContext(), + ObjCSubstitutionContext::Parameter); if (!S.getLangOpts().CPlusPlus || !paramType->isRecordType()) { ExprResult opResult = op; Sema::AssignConvertType assignResult @@ -819,7 +807,9 @@ ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) { // As a special case, if the method returns 'id', try to get // a better type from the property. if (RefExpr->isExplicitProperty() && result.get()->isRValue()) { - QualType propType = RefExpr->getExplicitProperty()->getType(); + QualType receiverType = RefExpr->getReceiverType(S.Context); + QualType propType = RefExpr->getExplicitProperty() + ->getUsageType(receiverType); if (result.get()->getType()->isObjCIdType()) { if (const ObjCObjectPointerType *ptr = propType->getAs<ObjCObjectPointerType>()) { @@ -1119,9 +1109,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { if (const ObjCObjectPointerType *PTy = BaseT->getAs<ObjCObjectPointerType>()) { ResultType = PTy->getPointeeType(); - if (const ObjCObjectType *iQFaceTy = - ResultType->getAsObjCQualifiedInterfaceType()) - ResultType = iQFaceTy->getBaseType(); } Sema::ObjCSubscriptKind Res = S.CheckSubscriptingKind(RefExpr->getKeyExpr()); @@ -1228,9 +1215,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { if (const ObjCObjectPointerType *PTy = BaseT->getAs<ObjCObjectPointerType>()) { ResultType = PTy->getPointeeType(); - if (const ObjCObjectType *iQFaceTy = - ResultType->getAsObjCQualifiedInterfaceType()) - ResultType = iQFaceTy->getBaseType(); } Sema::ObjCSubscriptKind Res = diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 6fca974d5b36..c4f6fd8df1c4 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -25,6 +25,7 @@ #include "clang/AST/StmtObjC.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -3649,6 +3650,10 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, else Diag(TryLoc, diag::err_seh_try_outside_functions); + // Reject __try on unsupported targets. + if (!Context.getTargetInfo().isSEHTrySupported()) + Diag(TryLoc, diag::err_seh_try_unsupported); + return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler); } diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index d19d8819d8e2..8e3e89f1e572 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -254,17 +254,19 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, << Info.getConstraintStr() << InputExpr->getSourceRange()); } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { - llvm::APSInt Result; - if (!InputExpr->EvaluateAsInt(Result, Context)) - return StmtError( - Diag(InputExpr->getLocStart(), diag::err_asm_immediate_expected) - << Info.getConstraintStr() << InputExpr->getSourceRange()); - if (Result.slt(Info.getImmConstantMin()) || - Result.sgt(Info.getImmConstantMax())) - return StmtError(Diag(InputExpr->getLocStart(), - diag::err_invalid_asm_value_for_constraint) - << Result.toString(10) << Info.getConstraintStr() - << InputExpr->getSourceRange()); + if (!InputExpr->isValueDependent()) { + llvm::APSInt Result; + if (!InputExpr->EvaluateAsInt(Result, Context)) + return StmtError( + Diag(InputExpr->getLocStart(), diag::err_asm_immediate_expected) + << Info.getConstraintStr() << InputExpr->getSourceRange()); + if (Result.slt(Info.getImmConstantMin()) || + Result.sgt(Info.getImmConstantMax())) + return StmtError(Diag(InputExpr->getLocStart(), + diag::err_invalid_asm_value_for_constraint) + << Result.toString(10) << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } } else { ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f4740a5cd855..035c37cfe6e9 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -893,6 +893,16 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, LookupQualifiedName(Previous, SemanticContext); } else { SemanticContext = CurContext; + + // C++14 [class.mem]p14: + // If T is the name of a class, then each of the following shall have a + // name different from T: + // -- every member template of class T + if (TUK != TUK_Friend && + DiagnoseClassNameShadow(SemanticContext, + DeclarationNameInfo(Name, NameLoc))) + return true; + LookupName(Previous, S); } @@ -947,8 +957,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Check that the chosen semantic context doesn't already contain a // declaration of this name as a non-tag type. - LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName, - ForRedeclaration); + Previous.clear(LookupOrdinaryName); DeclContext *LookupContext = SemanticContext; while (LookupContext->isTransparentContext()) LookupContext = LookupContext->getLookupParent(); @@ -962,9 +971,25 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } } else if (PrevDecl && - !isDeclInScope(PrevDecl, SemanticContext, S, SS.isValid())) + !isDeclInScope(Previous.getRepresentativeDecl(), SemanticContext, + S, SS.isValid())) PrevDecl = PrevClassTemplate = nullptr; + if (auto *Shadow = dyn_cast_or_null<UsingShadowDecl>( + PrevDecl ? Previous.getRepresentativeDecl() : nullptr)) { + if (SS.isEmpty() && + !(PrevClassTemplate && + PrevClassTemplate->getDeclContext()->getRedeclContext()->Equals( + SemanticContext->getRedeclContext()))) { + Diag(KWLoc, diag::err_using_decl_conflict_reverse); + Diag(Shadow->getTargetDecl()->getLocation(), + diag::note_using_decl_target); + Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; + // Recover by ignoring the old declaration. + PrevDecl = PrevClassTemplate = nullptr; + } + } + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. Skip this check // for a friend in a dependent context: the template parameter list itself @@ -983,7 +1008,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // template declaration (7.1.5.3). RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl(); if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, - TUK == TUK_Definition, KWLoc, *Name)) { + TUK == TUK_Definition, KWLoc, Name)) { Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName()); @@ -2285,7 +2310,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, assert(Id && "templated class must have an identifier"); if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, - TagLoc, *Id)) { + TagLoc, Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) << Result << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); @@ -6174,7 +6199,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, TUK == TUK_Definition, KWLoc, - *ClassTemplate->getIdentifier())) { + ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate << FixItHint::CreateReplacement(KWLoc, @@ -7210,7 +7235,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, /*isDefinition*/false, KWLoc, - *ClassTemplate->getIdentifier())) { + ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate << FixItHint::CreateReplacement(KWLoc, diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 7d58017a9bf0..c1961e516ddf 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -989,7 +989,7 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, if (Id && Keyword != ETK_None && Keyword != ETK_Typename) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, /*isDefinition*/false, - TagLocation, *Id)) { + TagLocation, Id)) { SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) << Id << FixItHint::CreateReplacement(SourceRange(TagLocation), diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 8d76f6920252..02a31ef8d79c 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -643,6 +643,9 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, NULLABILITY_TYPE_ATTRS_CASELIST: // Nullability specifiers cannot go after the declarator-id. + + // Objective-C __kindof does not get distributed. + case AttributeList::AT_ObjCKindOf: continue; default: @@ -738,6 +741,419 @@ static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS, } } +/// Apply Objective-C type arguments to the given type. +static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, + ArrayRef<TypeSourceInfo *> typeArgs, + SourceRange typeArgsRange, + bool failOnError = false) { + // We can only apply type arguments to an Objective-C class type. + const auto *objcObjectType = type->getAs<ObjCObjectType>(); + if (!objcObjectType || !objcObjectType->getInterface()) { + S.Diag(loc, diag::err_objc_type_args_non_class) + << type + << typeArgsRange; + + if (failOnError) + return QualType(); + return type; + } + + // The class type must be parameterized. + ObjCInterfaceDecl *objcClass = objcObjectType->getInterface(); + ObjCTypeParamList *typeParams = objcClass->getTypeParamList(); + if (!typeParams) { + S.Diag(loc, diag::err_objc_type_args_non_parameterized_class) + << objcClass->getDeclName() + << FixItHint::CreateRemoval(typeArgsRange); + + if (failOnError) + return QualType(); + + return type; + } + + // The type must not already be specialized. + if (objcObjectType->isSpecialized()) { + S.Diag(loc, diag::err_objc_type_args_specialized_class) + << type + << FixItHint::CreateRemoval(typeArgsRange); + + if (failOnError) + return QualType(); + + return type; + } + + // Check the type arguments. + SmallVector<QualType, 4> finalTypeArgs; + unsigned numTypeParams = typeParams->size(); + bool anyPackExpansions = false; + for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) { + TypeSourceInfo *typeArgInfo = typeArgs[i]; + QualType typeArg = typeArgInfo->getType(); + + // Type arguments cannot explicitly specify nullability. + if (auto nullability = AttributedType::stripOuterNullability(typeArg)) { + SourceLocation nullabilityLoc + = typeArgInfo->getTypeLoc().findNullabilityLoc(); + SourceLocation diagLoc = nullabilityLoc.isValid()? nullabilityLoc + : typeArgInfo->getTypeLoc().getLocStart(); + S.Diag(diagLoc, + diag::err_type_arg_explicit_nullability) + << typeArg + << FixItHint::CreateRemoval(nullabilityLoc); + } + + finalTypeArgs.push_back(typeArg); + + if (typeArg->getAs<PackExpansionType>()) + anyPackExpansions = true; + + // Find the corresponding type parameter, if there is one. + ObjCTypeParamDecl *typeParam = nullptr; + if (!anyPackExpansions) { + if (i < numTypeParams) { + typeParam = typeParams->begin()[i]; + } else { + // Too many arguments. + S.Diag(loc, diag::err_objc_type_args_wrong_arity) + << false + << objcClass->getDeclName() + << (unsigned)typeArgs.size() + << numTypeParams; + S.Diag(objcClass->getLocation(), diag::note_previous_decl) + << objcClass; + + if (failOnError) + return QualType(); + + return type; + } + } + + // Objective-C object pointer types must be substitutable for the bounds. + if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) { + // If we don't have a type parameter to match against, assume + // everything is fine. There was a prior pack expansion that + // means we won't be able to match anything. + if (!typeParam) { + assert(anyPackExpansions && "Too many arguments?"); + continue; + } + + // Retrieve the bound. + QualType bound = typeParam->getUnderlyingType(); + const auto *boundObjC = bound->getAs<ObjCObjectPointerType>(); + + // Determine whether the type argument is substitutable for the bound. + if (typeArgObjC->isObjCIdType()) { + // When the type argument is 'id', the only acceptable type + // parameter bound is 'id'. + if (boundObjC->isObjCIdType()) + continue; + } else if (S.Context.canAssignObjCInterfaces(boundObjC, typeArgObjC)) { + // Otherwise, we follow the assignability rules. + continue; + } + + // Diagnose the mismatch. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_does_not_match_bound) + << typeArg << bound << typeParam->getDeclName(); + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) + << typeParam->getDeclName(); + + if (failOnError) + return QualType(); + + return type; + } + + // Block pointer types are permitted for unqualified 'id' bounds. + if (typeArg->isBlockPointerType()) { + // If we don't have a type parameter to match against, assume + // everything is fine. There was a prior pack expansion that + // means we won't be able to match anything. + if (!typeParam) { + assert(anyPackExpansions && "Too many arguments?"); + continue; + } + + // Retrieve the bound. + QualType bound = typeParam->getUnderlyingType(); + if (bound->isBlockCompatibleObjCPointerType(S.Context)) + continue; + + // Diagnose the mismatch. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_does_not_match_bound) + << typeArg << bound << typeParam->getDeclName(); + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) + << typeParam->getDeclName(); + + if (failOnError) + return QualType(); + + return type; + } + + // Dependent types will be checked at instantiation time. + if (typeArg->isDependentType()) { + continue; + } + + // Diagnose non-id-compatible type arguments. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_not_id_compatible) + << typeArg + << typeArgInfo->getTypeLoc().getSourceRange(); + + if (failOnError) + return QualType(); + + return type; + } + + // Make sure we didn't have the wrong number of arguments. + if (!anyPackExpansions && finalTypeArgs.size() != numTypeParams) { + S.Diag(loc, diag::err_objc_type_args_wrong_arity) + << (typeArgs.size() < typeParams->size()) + << objcClass->getDeclName() + << (unsigned)finalTypeArgs.size() + << (unsigned)numTypeParams; + S.Diag(objcClass->getLocation(), diag::note_previous_decl) + << objcClass; + + if (failOnError) + return QualType(); + + return type; + } + + // Success. Form the specialized type. + return S.Context.getObjCObjectType(type, finalTypeArgs, { }, false); +} + +/// Apply Objective-C protocol qualifiers to the given type. +static QualType applyObjCProtocolQualifiers( + Sema &S, SourceLocation loc, SourceRange range, QualType type, + ArrayRef<ObjCProtocolDecl *> protocols, + const SourceLocation *protocolLocs, + bool failOnError = false) { + ASTContext &ctx = S.Context; + if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){ + // FIXME: Check for protocols to which the class type is already + // known to conform. + + return ctx.getObjCObjectType(objT->getBaseType(), + objT->getTypeArgsAsWritten(), + protocols, + objT->isKindOfTypeAsWritten()); + } + + if (type->isObjCObjectType()) { + // Silently overwrite any existing protocol qualifiers. + // TODO: determine whether that's the right thing to do. + + // FIXME: Check for protocols to which the class type is already + // known to conform. + return ctx.getObjCObjectType(type, { }, protocols, false); + } + + // id<protocol-list> + if (type->isObjCIdType()) { + const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); + type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols, + objPtr->isKindOfType()); + return ctx.getObjCObjectPointerType(type); + } + + // Class<protocol-list> + if (type->isObjCClassType()) { + const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); + type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols, + objPtr->isKindOfType()); + return ctx.getObjCObjectPointerType(type); + } + + S.Diag(loc, diag::err_invalid_protocol_qualifiers) + << range; + + if (failOnError) + return QualType(); + + return type; +} + +QualType Sema::BuildObjCObjectType(QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc, + bool FailOnError) { + QualType Result = BaseType; + if (!TypeArgs.empty()) { + Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs, + SourceRange(TypeArgsLAngleLoc, + TypeArgsRAngleLoc), + FailOnError); + if (FailOnError && Result.isNull()) + return QualType(); + } + + if (!Protocols.empty()) { + Result = applyObjCProtocolQualifiers(*this, Loc, + SourceRange(ProtocolLAngleLoc, + ProtocolRAngleLoc), + Result, Protocols, + ProtocolLocs.data(), + FailOnError); + if (FailOnError && Result.isNull()) + return QualType(); + } + + return Result; +} + +TypeResult Sema::actOnObjCProtocolQualifierType( + SourceLocation lAngleLoc, + ArrayRef<Decl *> protocols, + ArrayRef<SourceLocation> protocolLocs, + SourceLocation rAngleLoc) { + // Form id<protocol-list>. + QualType Result = Context.getObjCObjectType( + Context.ObjCBuiltinIdTy, { }, + llvm::makeArrayRef( + (ObjCProtocolDecl * const *)protocols.data(), + protocols.size()), + false); + Result = Context.getObjCObjectPointerType(Result); + + TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); + TypeLoc ResultTL = ResultTInfo->getTypeLoc(); + + auto ObjCObjectPointerTL = ResultTL.castAs<ObjCObjectPointerTypeLoc>(); + ObjCObjectPointerTL.setStarLoc(SourceLocation()); // implicit + + auto ObjCObjectTL = ObjCObjectPointerTL.getPointeeLoc() + .castAs<ObjCObjectTypeLoc>(); + ObjCObjectTL.setHasBaseTypeAsWritten(false); + ObjCObjectTL.getBaseLoc().initialize(Context, SourceLocation()); + + // No type arguments. + ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation()); + ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation()); + + // Fill in protocol qualifiers. + ObjCObjectTL.setProtocolLAngleLoc(lAngleLoc); + ObjCObjectTL.setProtocolRAngleLoc(rAngleLoc); + for (unsigned i = 0, n = protocols.size(); i != n; ++i) + ObjCObjectTL.setProtocolLoc(i, protocolLocs[i]); + + // We're done. Return the completed type to the parser. + return CreateParsedType(Result, ResultTInfo); +} + +TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( + Scope *S, + SourceLocation Loc, + ParsedType BaseType, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<ParsedType> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<Decl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc) { + TypeSourceInfo *BaseTypeInfo = nullptr; + QualType T = GetTypeFromParser(BaseType, &BaseTypeInfo); + if (T.isNull()) + return true; + + // Handle missing type-source info. + if (!BaseTypeInfo) + BaseTypeInfo = Context.getTrivialTypeSourceInfo(T, Loc); + + // Extract type arguments. + SmallVector<TypeSourceInfo *, 4> ActualTypeArgInfos; + for (unsigned i = 0, n = TypeArgs.size(); i != n; ++i) { + TypeSourceInfo *TypeArgInfo = nullptr; + QualType TypeArg = GetTypeFromParser(TypeArgs[i], &TypeArgInfo); + if (TypeArg.isNull()) { + ActualTypeArgInfos.clear(); + break; + } + + assert(TypeArgInfo && "No type source info?"); + ActualTypeArgInfos.push_back(TypeArgInfo); + } + + // Build the object type. + QualType Result = BuildObjCObjectType( + T, BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(), + TypeArgsLAngleLoc, ActualTypeArgInfos, TypeArgsRAngleLoc, + ProtocolLAngleLoc, + llvm::makeArrayRef((ObjCProtocolDecl * const *)Protocols.data(), + Protocols.size()), + ProtocolLocs, ProtocolRAngleLoc, + /*FailOnError=*/false); + + if (Result == T) + return BaseType; + + // Create source information for this type. + TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); + TypeLoc ResultTL = ResultTInfo->getTypeLoc(); + + // For id<Proto1, Proto2> or Class<Proto1, Proto2>, we'll have an + // object pointer type. Fill in source information for it. + if (auto ObjCObjectPointerTL = ResultTL.getAs<ObjCObjectPointerTypeLoc>()) { + // The '*' is implicit. + ObjCObjectPointerTL.setStarLoc(SourceLocation()); + ResultTL = ObjCObjectPointerTL.getPointeeLoc(); + } + + auto ObjCObjectTL = ResultTL.castAs<ObjCObjectTypeLoc>(); + + // Type argument information. + if (ObjCObjectTL.getNumTypeArgs() > 0) { + assert(ObjCObjectTL.getNumTypeArgs() == ActualTypeArgInfos.size()); + ObjCObjectTL.setTypeArgsLAngleLoc(TypeArgsLAngleLoc); + ObjCObjectTL.setTypeArgsRAngleLoc(TypeArgsRAngleLoc); + for (unsigned i = 0, n = ActualTypeArgInfos.size(); i != n; ++i) + ObjCObjectTL.setTypeArgTInfo(i, ActualTypeArgInfos[i]); + } else { + ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation()); + ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation()); + } + + // Protocol qualifier information. + if (ObjCObjectTL.getNumProtocols() > 0) { + assert(ObjCObjectTL.getNumProtocols() == Protocols.size()); + ObjCObjectTL.setProtocolLAngleLoc(ProtocolLAngleLoc); + ObjCObjectTL.setProtocolRAngleLoc(ProtocolRAngleLoc); + for (unsigned i = 0, n = Protocols.size(); i != n; ++i) + ObjCObjectTL.setProtocolLoc(i, ProtocolLocs[i]); + } else { + ObjCObjectTL.setProtocolLAngleLoc(SourceLocation()); + ObjCObjectTL.setProtocolRAngleLoc(SourceLocation()); + } + + // Base type. + ObjCObjectTL.setHasBaseTypeAsWritten(true); + if (ObjCObjectTL.getType() == T) + ObjCObjectTL.getBaseLoc().initializeFullCopy(BaseTypeInfo->getTypeLoc()); + else + ObjCObjectTL.getBaseLoc().initialize(Context, Loc); + + // We're done. Return the completed type to the parser. + return CreateParsedType(Result, ResultTInfo); +} + /// \brief Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -801,15 +1217,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.Char32Ty; break; case DeclSpec::TST_unspecified: - // "<proto1,proto2>" is an objc qualified ID with a missing id. - if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl*const*)PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - break; - } - // If this is a missing declspec in a block literal return context, then it // is inferred from the return statements inside the block. // The declspec is always missing in a lambda expr context; it is either @@ -967,37 +1374,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); Result = S.GetTypeFromParser(DS.getRepAsType()); - if (Result.isNull()) + if (Result.isNull()) { declarator.setInvalidType(true); - else if (DeclSpec::ProtocolQualifierListTy PQ - = DS.getProtocolQualifiers()) { - if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) { - // Silently drop any existing protocol qualifiers. - // TODO: determine whether that's the right thing to do. - if (ObjT->getNumProtocols()) - Result = ObjT->getBaseType(); - - if (DS.getNumProtocolQualifiers()) - Result = Context.getObjCObjectType(Result, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - } else if (Result->isObjCIdType()) { - // id<protocol-list> - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - } else if (Result->isObjCClassType()) { - // Class<protocol-list> - Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - } else { - S.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) - << DS.getSourceRange(); - declarator.setInvalidType(true); - } } else if (S.getLangOpts().OpenCL) { if (const AtomicType *AT = Result->getAs<AtomicType>()) { const BuiltinType *BT = AT->getValueType()->getAs<BuiltinType>(); @@ -3097,6 +3475,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, spliceAttrIntoList(*nullabilityAttr, attrs); + if (inferNullabilityCS) { + state.getDeclarator().getMutableDeclSpec().getObjCQualifiers() + ->setObjCDeclQualifier(ObjCDeclSpec::DQ_CSNullability); + } + if (inferNullabilityInnerOnly) inferNullabilityInnerOnlyComplete = true; return nullabilityAttr; @@ -3116,7 +3499,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case CAMN_Yes: checkNullabilityConsistency(state, pointerKind, pointerLoc); } - return nullptr; }; @@ -4058,6 +4440,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_TypeNullable; case AttributedType::attr_null_unspecified: return AttributeList::AT_TypeNullUnspecified; + case AttributedType::attr_objc_kindof: + return AttributeList::AT_ObjCKindOf; } llvm_unreachable("unexpected attribute kind!"); } @@ -4129,32 +4513,14 @@ namespace { TL.setNameEndLoc(DS.getLocEnd()); } void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { - // Handle the base type, which might not have been written explicitly. - if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { - TL.setHasBaseTypeAsWritten(false); - TL.getBaseLoc().initialize(Context, SourceLocation()); - } else { - TL.setHasBaseTypeAsWritten(true); - Visit(TL.getBaseLoc()); - } - - // Protocol qualifiers. - 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()); - } + TypeSourceInfo *RepTInfo = nullptr; + Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo); + TL.copy(RepTInfo->getTypeLoc()); } void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - TL.setStarLoc(SourceLocation()); - Visit(TL.getPointeeLoc()); + TypeSourceInfo *RepTInfo = nullptr; + Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo); + TL.copy(RepTInfo->getTypeLoc()); } void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { TypeSourceInfo *TInfo = nullptr; @@ -5160,6 +5526,44 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type, return false; } +bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) { + // Find out if it's an Objective-C object or object pointer type; + const ObjCObjectPointerType *ptrType = type->getAs<ObjCObjectPointerType>(); + const ObjCObjectType *objType = ptrType ? ptrType->getObjectType() + : type->getAs<ObjCObjectType>(); + + // If not, we can't apply __kindof. + if (!objType) { + // FIXME: Handle dependent types that aren't yet object types. + Diag(loc, diag::err_objc_kindof_nonobject) + << type; + return true; + } + + // Rebuild the "equivalent" type, which pushes __kindof down into + // the object type. + QualType equivType = Context.getObjCObjectType(objType->getBaseType(), + objType->getTypeArgsAsWritten(), + objType->getProtocols(), + /*isKindOf=*/true); + + // If we started with an object pointer type, rebuild it. + if (ptrType) { + equivType = Context.getObjCObjectPointerType(equivType); + if (auto nullability = type->getNullability(Context)) { + auto attrKind = AttributedType::getNullabilityAttrKind(*nullability); + equivType = Context.getAttributedType(attrKind, equivType, equivType); + } + } + + // Build the attributed type to record where __kindof occurred. + type = Context.getAttributedType(AttributedType::attr_objc_kindof, + type, + equivType); + + return false; +} + /// Map a nullability attribute kind to a nullability kind. static NullabilityKind mapNullabilityAttrKind(AttributeList::Kind kind) { switch (kind) { @@ -5770,6 +6174,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; + NULLABILITY_TYPE_ATTRS_CASELIST: // Either add nullability here or try to distribute it. We // don't want to distribute the nullability specifier past any @@ -5788,6 +6193,28 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } break; + case AttributeList::AT_ObjCKindOf: + // '__kindof' must be part of the decl-specifiers. + switch (TAL) { + case TAL_DeclSpec: + break; + + case TAL_DeclChunk: + case TAL_DeclName: + state.getSema().Diag(attr.getLoc(), + diag::err_objc_kindof_wrong_position) + << FixItHint::CreateRemoval(attr.getLoc()) + << FixItHint::CreateInsertion( + state.getDeclarator().getDeclSpec().getLocStart(), "__kindof "); + break; + } + + // Apply it regardless. + if (state.getSema().checkObjCKindOfType(type, attr.getLoc())) + attr.setInvalid(); + attr.setUsedAsTypeAttr(); + break; + case AttributeList::AT_NSReturnsRetained: if (!state.getSema().getLangOpts().ObjCAutoRefCount) break; @@ -5942,7 +6369,12 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, /// \param D The definition of the entity. /// \param Suggested Filled in with the declaration that should be made visible /// in order to provide a definition of this entity. -bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) { +/// \param OnlyNeedComplete If \c true, we only need the type to be complete, +/// not defined. This only matters for enums with a fixed underlying +/// type, since in all other cases, a type is complete if and only if it +/// is defined. +bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete) { // Easy case: if we don't have modules, all declarations are visible. if (!getLangOpts().Modules && !getLangOpts().ModulesLocalVisibility) return true; @@ -5960,11 +6392,13 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) { } else if (auto *ED = dyn_cast<EnumDecl>(D)) { while (auto *NewED = ED->getInstantiatedFromMemberEnum()) ED = NewED; - if (ED->isFixed()) { - // If the enum has a fixed underlying type, any declaration of it will do. + if (OnlyNeedComplete && ED->isFixed()) { + // If the enum has a fixed underlying type, and we're only looking for a + // complete type (not a definition), any visible declaration of it will + // do. *Suggested = nullptr; for (auto *Redecl : ED->redecls()) { - if (LookupResult::isVisible(*this, Redecl)) + if (isVisible(Redecl)) return true; if (Redecl->isThisDeclarationADefinition() || (Redecl->isCanonicalDecl() && !*Suggested)) @@ -5977,14 +6411,14 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) { assert(D && "missing definition for pattern of instantiated definition"); *Suggested = D; - if (LookupResult::isVisible(*this, D)) + if (isVisible(D)) return true; // The external source may have additional definitions of this type that are // visible, so complete the redeclaration chain now and ask again. if (auto *Source = Context.getExternalSource()) { Source->CompleteRedeclChain(D); - return LookupResult::isVisible(*this, D); + return isVisible(D); } return false; @@ -6038,7 +6472,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; if (!Diagnoser.Suppressed && Def && - !hasVisibleDefinition(Def, &SuggestedDef)) + !hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true)) diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true); // We lock in the inheritance model once somebody has asked us to ensure diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 80896be981d1..6e193a3529c9 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -685,6 +685,27 @@ public: QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType, SourceLocation Sigil); + /// \brief Build an Objective-C object type. + /// + /// By default, performs semantic analysis when building the object type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildObjCObjectType(QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc); + + /// \brief Build a new Objective-C object pointer type given the pointee type. + /// + /// By default, directly builds the pointer type, with no additional semantic + /// analysis. + QualType RebuildObjCObjectPointerType(QualType PointeeType, + SourceLocation Star); + /// \brief Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type /// qualifiers. @@ -989,7 +1010,7 @@ public: } if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false, - IdLoc, *Id)) { + IdLoc, Id)) { SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id; SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); return QualType(); @@ -5606,18 +5627,153 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, ObjCObjectTypeLoc TL) { - // ObjCObjectType is never dependent. - TLB.pushFullCopy(TL); - return TL.getType(); + // Transform base type. + QualType BaseType = getDerived().TransformType(TLB, TL.getBaseLoc()); + if (BaseType.isNull()) + return QualType(); + + bool AnyChanged = BaseType != TL.getBaseLoc().getType(); + + // Transform type arguments. + SmallVector<TypeSourceInfo *, 4> NewTypeArgInfos; + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) { + TypeSourceInfo *TypeArgInfo = TL.getTypeArgTInfo(i); + TypeLoc TypeArgLoc = TypeArgInfo->getTypeLoc(); + QualType TypeArg = TypeArgInfo->getType(); + if (auto PackExpansionLoc = TypeArgLoc.getAs<PackExpansionTypeLoc>()) { + AnyChanged = true; + + // We have a pack expansion. Instantiate it. + const auto *PackExpansion = PackExpansionLoc.getType() + ->castAs<PackExpansionType>(); + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), + Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can + // and should be expanded. + TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc(); + bool Expand = false; + bool RetainExpansion = false; + Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); + if (getDerived().TryExpandParameterPacks( + PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(), + Unexpanded, Expand, RetainExpansion, NumExpansions)) + return QualType(); + + if (!Expand) { + // We can't expand this pack expansion into separate arguments yet; + // just substitute into the pattern and create a new pack expansion + // type. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + + TypeLocBuilder TypeArgBuilder; + TypeArgBuilder.reserve(PatternLoc.getFullDataSize()); + QualType NewPatternType = getDerived().TransformType(TypeArgBuilder, + PatternLoc); + if (NewPatternType.isNull()) + return QualType(); + + QualType NewExpansionType = SemaRef.Context.getPackExpansionType( + NewPatternType, NumExpansions); + auto NewExpansionLoc = TLB.push<PackExpansionTypeLoc>(NewExpansionType); + NewExpansionLoc.setEllipsisLoc(PackExpansionLoc.getEllipsisLoc()); + NewTypeArgInfos.push_back( + TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewExpansionType)); + continue; + } + + // Substitute into the pack expansion pattern for each slice of the + // pack. + for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx); + + TypeLocBuilder TypeArgBuilder; + TypeArgBuilder.reserve(PatternLoc.getFullDataSize()); + + QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, + PatternLoc); + if (NewTypeArg.isNull()) + return QualType(); + + NewTypeArgInfos.push_back( + TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg)); + } + + continue; + } + + TypeLocBuilder TypeArgBuilder; + TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize()); + QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc); + if (NewTypeArg.isNull()) + return QualType(); + + // If nothing changed, just keep the old TypeSourceInfo. + if (NewTypeArg == TypeArg) { + NewTypeArgInfos.push_back(TypeArgInfo); + continue; + } + + NewTypeArgInfos.push_back( + TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg)); + AnyChanged = true; + } + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || AnyChanged) { + // Rebuild the type. + Result = getDerived().RebuildObjCObjectType( + BaseType, + TL.getLocStart(), + TL.getTypeArgsLAngleLoc(), + NewTypeArgInfos, + TL.getTypeArgsRAngleLoc(), + TL.getProtocolLAngleLoc(), + llvm::makeArrayRef(TL.getTypePtr()->qual_begin(), + TL.getNumProtocols()), + TL.getProtocolLocs(), + TL.getProtocolRAngleLoc()); + + if (Result.isNull()) + return QualType(); + } + + ObjCObjectTypeLoc NewT = TLB.push<ObjCObjectTypeLoc>(Result); + assert(TL.hasBaseTypeAsWritten() && "Can't be dependent"); + NewT.setHasBaseTypeAsWritten(true); + NewT.setTypeArgsLAngleLoc(TL.getTypeArgsLAngleLoc()); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) + NewT.setTypeArgTInfo(i, NewTypeArgInfos[i]); + NewT.setTypeArgsRAngleLoc(TL.getTypeArgsRAngleLoc()); + NewT.setProtocolLAngleLoc(TL.getProtocolLAngleLoc()); + for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i) + NewT.setProtocolLoc(i, TL.getProtocolLoc(i)); + NewT.setProtocolRAngleLoc(TL.getProtocolRAngleLoc()); + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, ObjCObjectPointerTypeLoc TL) { - // ObjCObjectPointerType is never dependent. - TLB.pushFullCopy(TL); - return TL.getType(); + 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().RebuildObjCObjectPointerType(PointeeType, + TL.getStarLoc()); + if (Result.isNull()) + return QualType(); + } + + ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result); + NewT.setStarLoc(TL.getStarLoc()); + return Result; } //===----------------------------------------------------------------------===// @@ -10494,6 +10650,31 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, } template<typename Derived> +QualType TreeTransform<Derived>::RebuildObjCObjectType( + QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc) { + return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, + TypeArgs, TypeArgsRAngleLoc, + ProtocolLAngleLoc, Protocols, ProtocolLocs, + ProtocolRAngleLoc, + /*FailOnError=*/true); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildObjCObjectPointerType( + QualType PointeeType, + SourceLocation Star) { + return SemaRef.Context.getObjCObjectPointerType(PointeeType); +} + +template<typename Derived> QualType TreeTransform<Derived>::RebuildArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 85c574c2021a..b1bf4a6bff8b 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -221,6 +221,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { // redeclarable. case Decl::ImplicitParam: case Decl::ParmVar: + case Decl::ObjCTypeParam: return false; } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 48a898cb30da..3045629a333e 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -845,7 +845,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, } unsigned -ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const { +ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) { llvm::FoldingSetNodeID ID; ID.AddInteger(Key.Kind); @@ -874,7 +874,7 @@ ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const { ASTDeclContextNameLookupTrait::internal_key_type ASTDeclContextNameLookupTrait::GetInternalKey( - const external_key_type& Name) const { + const external_key_type& Name) { DeclNameKey Key; Key.Kind = Name.getNameKind(); switch (Name.getNameKind()) { @@ -1644,6 +1644,7 @@ namespace { /// \brief Visitor class used to look up identifirs in an AST file. class IdentifierLookupVisitor { StringRef Name; + unsigned NameHash; unsigned PriorGeneration; unsigned &NumIdentifierLookups; unsigned &NumIdentifierLookupHits; @@ -1653,7 +1654,8 @@ namespace { IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration, unsigned &NumIdentifierLookups, unsigned &NumIdentifierLookupHits) - : Name(Name), PriorGeneration(PriorGeneration), + : Name(Name), NameHash(ASTIdentifierLookupTrait::ComputeHash(Name)), + PriorGeneration(PriorGeneration), NumIdentifierLookups(NumIdentifierLookups), NumIdentifierLookupHits(NumIdentifierLookupHits), Found() @@ -1676,7 +1678,8 @@ namespace { ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), M, This->Found); ++This->NumIdentifierLookups; - ASTIdentifierLookupTable::iterator Pos = IdTable->find(This->Name,&Trait); + ASTIdentifierLookupTable::iterator Pos = + IdTable->find_hashed(This->Name, This->NameHash, &Trait); if (Pos == IdTable->end()) return false; @@ -3976,8 +3979,7 @@ bool ASTReader::readASTFileControlBlock( // Initialize the stream llvm::BitstreamReader StreamFile; - StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(), - (const unsigned char *)(*Buffer)->getBufferEnd()); + PCHContainerOps.ExtractPCH((*Buffer)->getMemBufferRef(), StreamFile); BitstreamCursor Stream(StreamFile); // Sniff for the signature. @@ -5263,11 +5265,16 @@ QualType ASTReader::readTypeRecord(unsigned Index) { case TYPE_OBJC_OBJECT: { unsigned Idx = 0; QualType Base = readType(*Loc.F, Record, Idx); + unsigned NumTypeArgs = Record[Idx++]; + SmallVector<QualType, 4> TypeArgs; + for (unsigned I = 0; I != NumTypeArgs; ++I) + TypeArgs.push_back(readType(*Loc.F, Record, Idx)); unsigned NumProtos = Record[Idx++]; SmallVector<ObjCProtocolDecl*, 4> Protos; for (unsigned I = 0; I != NumProtos; ++I) Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); - return Context.getObjCObjectType(Base, Protos.data(), NumProtos); + bool IsKindOf = Record[Idx++]; + return Context.getObjCObjectType(Base, TypeArgs, Protos, IsKindOf); } case TYPE_OBJC_OBJECT_POINTER: { @@ -5646,8 +5653,12 @@ void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { TL.setHasBaseTypeAsWritten(Record[Idx++]); - TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); - TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setTypeArgsLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setTypeArgsRAngleLoc(ReadSourceLocation(Record, Idx)); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + TL.setTypeArgTInfo(i, Reader.GetTypeSourceInfo(F, Record, Idx)); + TL.setProtocolLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setProtocolRAngleLoc(ReadSourceLocation(Record, Idx)); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx)); } @@ -5987,9 +5998,8 @@ bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID, if (ID < NUM_PREDEF_DECL_IDS) return false; - GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID); - assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); - return &M == I->second; + return ID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID && + ID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls; } ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) { @@ -6063,7 +6073,7 @@ Decl *ASTReader::GetExistingDecl(DeclID ID) { if (D) { // Track that we have merged the declaration with ID \p ID into the // pre-existing predefined declaration \p D. - auto &Merged = MergedDecls[D->getCanonicalDecl()]; + auto &Merged = KeyDecls[D->getCanonicalDecl()]; if (Merged.empty()) Merged.push_back(ID); } @@ -6288,6 +6298,27 @@ void ASTReader::FindFileRegionDecls(FileID File, Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt))); } +/// \brief Retrieve the "definitive" module file for the definition of the +/// given declaration context, if there is one. +/// +/// The "definitive" module file is the only place where we need to look to +/// find information about the declarations within the given declaration +/// context. For example, C++ and Objective-C classes, C structs/unions, and +/// Objective-C protocols, categories, and extensions are all defined in a +/// single place in the source code, so they have definitive module files +/// associated with them. C++ namespaces, on the other hand, can have +/// definitions in multiple different module files. +/// +/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's +/// NDEBUG checking. +static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC, + ASTReader &Reader) { + if (const DeclContext *DefDC = getDefinitiveDeclContext(DC)) + return Reader.getOwningModuleFile(cast<Decl>(DefDC)); + + return nullptr; +} + namespace { /// \brief ModuleFile visitor used to perform name lookup into a /// declaration context. @@ -6295,18 +6326,38 @@ namespace { ASTReader &Reader; ArrayRef<const DeclContext *> Contexts; DeclarationName Name; + ASTDeclContextNameLookupTrait::DeclNameKey NameKey; + unsigned NameHash; SmallVectorImpl<NamedDecl *> &Decls; llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet; public: DeclContextNameLookupVisitor(ASTReader &Reader, - ArrayRef<const DeclContext *> Contexts, DeclarationName Name, SmallVectorImpl<NamedDecl *> &Decls, llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet) - : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls), - DeclSet(DeclSet) { } + : Reader(Reader), Name(Name), + NameKey(ASTDeclContextNameLookupTrait::GetInternalKey(Name)), + NameHash(ASTDeclContextNameLookupTrait::ComputeHash(NameKey)), + Decls(Decls), DeclSet(DeclSet) {} + + void visitContexts(ArrayRef<const DeclContext*> Contexts) { + if (Contexts.empty()) + return; + this->Contexts = Contexts; + + // If we can definitively determine which module file to look into, + // only look there. Otherwise, look in all module files. + ModuleFile *Definitive; + if (Contexts.size() == 1 && + (Definitive = getDefinitiveModuleFileFor(Contexts[0], Reader))) { + visit(*Definitive, this); + } else { + Reader.getModuleManager().visit(&visit, this); + } + } + private: static bool visit(ModuleFile &M, void *UserData) { DeclContextNameLookupVisitor *This = static_cast<DeclContextNameLookupVisitor *>(UserData); @@ -6331,7 +6382,7 @@ namespace { ASTDeclContextNameLookupTable *LookupTable = Info->second.NameLookupTableData; ASTDeclContextNameLookupTable::iterator Pos - = LookupTable->find(This->Name); + = LookupTable->find_hashed(This->NameKey, This->NameHash); if (Pos == LookupTable->end()) return false; @@ -6363,27 +6414,6 @@ namespace { }; } -/// \brief Retrieve the "definitive" module file for the definition of the -/// given declaration context, if there is one. -/// -/// The "definitive" module file is the only place where we need to look to -/// find information about the declarations within the given declaration -/// context. For example, C++ and Objective-C classes, C structs/unions, and -/// Objective-C protocols, categories, and extensions are all defined in a -/// single place in the source code, so they have definitive module files -/// associated with them. C++ namespaces, on the other hand, can have -/// definitions in multiple different module files. -/// -/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's -/// NDEBUG checking. -static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC, - ASTReader &Reader) { - if (const DeclContext *DefDC = getDefinitiveDeclContext(DC)) - return Reader.getOwningModuleFile(cast<Decl>(DefDC)); - - return nullptr; -} - bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { @@ -6405,28 +6435,15 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, Contexts.push_back(DC); if (DC->isNamespace()) { - auto Merged = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); - if (Merged != MergedDecls.end()) { - for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) - Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I]))); + auto Key = KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC))); + if (Key != KeyDecls.end()) { + for (unsigned I = 0, N = Key->second.size(); I != N; ++I) + Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I]))); } } - auto LookUpInContexts = [&](ArrayRef<const DeclContext*> Contexts) { - DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls, DeclSet); - - // If we can definitively determine which module file to look into, - // only look there. Otherwise, look in all module files. - ModuleFile *Definitive; - if (Contexts.size() == 1 && - (Definitive = getDefinitiveModuleFileFor(Contexts[0], *this))) { - DeclContextNameLookupVisitor::visit(*Definitive, &Visitor); - } else { - ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); - } - }; - - LookUpInContexts(Contexts); + DeclContextNameLookupVisitor Visitor(*this, Name, Decls, DeclSet); + Visitor.visitContexts(Contexts); // If this might be an implicit special member function, then also search // all merged definitions of the surrounding class. We need to search them @@ -6437,7 +6454,7 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, if (Merged != MergedLookups.end()) { for (unsigned I = 0; I != Merged->second.size(); ++I) { const DeclContext *Context = Merged->second[I]; - LookUpInContexts(Context); + Visitor.visitContexts(Context); // We might have just added some more merged lookups. If so, our // iterator is now invalid, so grab a fresh one before continuing. Merged = MergedLookups.find(DC); @@ -6525,11 +6542,11 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { Contexts.push_back(DC); if (DC->isNamespace()) { - MergedDeclsMap::iterator Merged - = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); - if (Merged != MergedDecls.end()) { - for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) - Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I]))); + KeyDeclsMap::iterator Key = + KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC))); + if (Key != KeyDecls.end()) { + for (unsigned I = 0, N = Key->second.size(); I != N; ++I) + Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I]))); } } @@ -8389,6 +8406,11 @@ void ASTReader::diagnoseOdrViolations() { } } +void ASTReader::StartedDeserializing() { + if (++NumCurrentElementsDeserializing == 1 && ReadTimer.get()) + ReadTimer->startTimer(); +} + void ASTReader::FinishedDeserializing() { assert(NumCurrentElementsDeserializing && "FinishedDeserializing not paired with StartedDeserializing"); @@ -8413,6 +8435,9 @@ void ASTReader::FinishedDeserializing() { diagnoseOdrViolations(); + if (ReadTimer) + ReadTimer->stopTimer(); + // We are not in recursive loading, so it's safe to pass the "interesting" // decls to the consumer. if (Consumer) @@ -8451,12 +8476,14 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot, bool DisableValidation, bool AllowASTWithCompilerErrors, bool AllowConfigurationMismatch, bool ValidateSystemInputs, - bool UseGlobalIndex) + bool UseGlobalIndex, + std::unique_ptr<llvm::Timer> ReadTimer) : Listener(new PCHValidator(PP, *this)), DeserializationListener(nullptr), OwnsDeserializationListener(false), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), PCHContainerOps(PCHContainerOps), Diags(PP.getDiagnostics()), SemaObj(nullptr), PP(PP), Context(Context), Consumer(nullptr), ModuleMgr(PP.getFileManager(), PCHContainerOps), + ReadTimer(std::move(ReadTimer)), isysroot(isysroot), DisableValidation(DisableValidation), AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), AllowConfigurationMismatch(AllowConfigurationMismatch), diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index b23c33c55188..1a0c5b58e7f6 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -128,20 +128,22 @@ namespace clang { GlobalDeclID FirstID; Decl *MergeWith; mutable bool Owning; + bool IsKeyDecl; Decl::Kind DeclKind; void operator=(RedeclarableResult &) = delete; public: RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID, - Decl *MergeWith, Decl::Kind DeclKind) + Decl *MergeWith, Decl::Kind DeclKind, + bool IsKeyDecl) : Reader(Reader), FirstID(FirstID), MergeWith(MergeWith), - Owning(true), DeclKind(DeclKind) {} + Owning(true), IsKeyDecl(IsKeyDecl), DeclKind(DeclKind) {} RedeclarableResult(RedeclarableResult &&Other) : Reader(Other.Reader), FirstID(Other.FirstID), MergeWith(Other.MergeWith), Owning(Other.Owning), - DeclKind(Other.DeclKind) { + IsKeyDecl(Other.IsKeyDecl), DeclKind(Other.DeclKind) { Other.Owning = false; } @@ -156,6 +158,9 @@ namespace clang { /// \brief Retrieve the first ID. GlobalDeclID getFirstID() const { return FirstID; } + /// \brief Is this declaration the key declaration? + bool isKeyDecl() const { return IsKeyDecl; } + /// \brief Get a known declaration that this should be merged with, if /// any. Decl *getKnownMergeTarget() const { return MergeWith; } @@ -348,10 +353,13 @@ namespace clang { void mergeTemplatePattern(RedeclarableTemplateDecl *D, RedeclarableTemplateDecl *Existing, - DeclID DsID); + DeclID DsID, bool IsKeyDecl); + + ObjCTypeParamList *ReadObjCTypeParamList(); // FIXME: Reorder according to DeclNodes.td? void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *D); void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); void VisitObjCIvarDecl(ObjCIvarDecl *D); @@ -899,18 +907,49 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs); } +void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { + VisitTypedefNameDecl(D); + D->Variance = Record[Idx++]; + D->Index = Record[Idx++]; + D->VarianceLoc = ReadSourceLocation(Record, Idx); + D->ColonLoc = ReadSourceLocation(Record, Idx); +} + void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { VisitNamedDecl(CD); CD->setAtStartLoc(ReadSourceLocation(Record, Idx)); CD->setAtEndRange(ReadSourceRange(Record, Idx)); } +ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() { + unsigned numParams = Record[Idx++]; + if (numParams == 0) + return nullptr; + + SmallVector<ObjCTypeParamDecl *, 4> typeParams; + typeParams.reserve(numParams); + for (unsigned i = 0; i != numParams; ++i) { + auto typeParam = ReadDeclAs<ObjCTypeParamDecl>(Record, Idx); + if (!typeParam) + return nullptr; + + typeParams.push_back(typeParam); + } + + SourceLocation lAngleLoc = ReadSourceLocation(Record, Idx); + SourceLocation rAngleLoc = ReadSourceLocation(Record, Idx); + + return ObjCTypeParamList::create(Reader.getContext(), lAngleLoc, + typeParams, rAngleLoc); +} + void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { RedeclarableResult Redecl = VisitRedeclarable(ID); VisitObjCContainerDecl(ID); TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]); mergeRedeclarable(ID, Redecl); - + + ID->TypeParamList = ReadObjCTypeParamList(); if (Record[Idx++]) { // Read the definition. ID->allocateDefinitionData(); @@ -922,8 +961,7 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { ObjCInterfaceDecl::DefinitionData &Data = ID->data(); // Read the superclass. - Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx); - Data.SuperClassLoc = ReadSourceLocation(Record, Idx); + Data.SuperClassTInfo = GetTypeSourceInfo(Record, Idx); Data.EndLoc = ReadSourceLocation(Record, Idx); Data.HasDesignatedInitializers = Record[Idx++]; @@ -1020,6 +1058,7 @@ void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { Reader.CategoriesDeserialized.insert(CD); CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx); + CD->TypeParamList = ReadObjCTypeParamList(); unsigned NumProtoRefs = Record[Idx++]; SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; ProtoRefs.reserve(NumProtoRefs); @@ -2139,12 +2178,16 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { DeclID FirstDeclID = ReadDeclID(Record, Idx); Decl *MergeWith = nullptr; + bool IsKeyDecl = ThisDeclID == FirstDeclID; // 0 indicates that this declaration was the only declaration of its entity, // and is used for space optimization. - if (FirstDeclID == 0) + if (FirstDeclID == 0) { FirstDeclID = ThisDeclID; - else if (unsigned N = Record[Idx++]) { + IsKeyDecl = true; + } else if (unsigned N = Record[Idx++]) { + IsKeyDecl = false; + // We have some declarations that must be before us in our redeclaration // chain. Read them now, and remember that we ought to merge with one of // them. @@ -2170,7 +2213,7 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { // The result structure takes care to note that we need to load the // other declaration chains for this ID. return RedeclarableResult(Reader, FirstDeclID, MergeWith, - static_cast<T *>(D)->getKind()); + static_cast<T *>(D)->getKind(), IsKeyDecl); } /// \brief Attempts to merge the given declaration (D) with another declaration @@ -2209,11 +2252,12 @@ template<typename T> static T assert_cast(...) { /// declarations. void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D, RedeclarableTemplateDecl *Existing, - DeclID DsID) { + DeclID DsID, bool IsKeyDecl) { auto *DPattern = D->getTemplatedDecl(); auto *ExistingPattern = Existing->getTemplatedDecl(); RedeclarableResult Result(Reader, DPattern->getCanonicalDecl()->getGlobalID(), - /*MergeWith*/ExistingPattern, DPattern->getKind()); + /*MergeWith*/ExistingPattern, DPattern->getKind(), + IsKeyDecl); if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern)) { // Merge with any existing definition. @@ -2276,11 +2320,11 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing, if (auto *DTemplate = dyn_cast<RedeclarableTemplateDecl>(D)) mergeTemplatePattern( DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon), - TemplatePatternID); + TemplatePatternID, Redecl.isKeyDecl()); - // If this declaration was the canonical declaration, make a note of that. - if (DCanon == D) { - Reader.MergedDecls[ExistingCanon].push_back(Redecl.getFirstID()); + // If this declaration is a key declaration, make a note of that. + if (Redecl.isKeyDecl()) { + Reader.KeyDecls[ExistingCanon].push_back(Redecl.getFirstID()); if (Reader.PendingDeclChainsKnown.insert(ExistingCanon).second) Reader.PendingDeclChains.push_back(ExistingCanon); } @@ -3259,6 +3303,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_EMPTY: D = EmptyDecl::CreateDeserialized(Context, ID); break; + case DECL_OBJC_TYPE_PARAM: + D = ObjCTypeParamDecl::CreateDeserialized(Context, ID); + break; } assert(D && "Unknown declaration reading AST file"); @@ -3418,20 +3465,9 @@ namespace { M.RedeclarationsMap + M.LocalNumRedeclarationsInMap, Compare); if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap || - Result->FirstID != ID) { - // If we have a previously-canonical singleton declaration that was - // merged into another redeclaration chain, create a trivial chain - // for this single declaration so that it will get wired into the - // complete redeclaration chain. - if (GlobalID != CanonID && - GlobalID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID && - GlobalID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls) { - addToChain(Reader.GetDecl(GlobalID)); - } - + Result->FirstID != ID) return; - } - + // Dig out all of the redeclarations. unsigned Offset = Result->Offset; unsigned N = M.RedeclarationChains[Offset]; @@ -3472,8 +3508,6 @@ namespace { // Visit each of the declarations. for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I) searchForID(M, SearchDecls[I]); - // FIXME: If none of the SearchDecls had local IDs in this module, can - // we avoid searching any ancestor module files? return false; } @@ -3494,9 +3528,9 @@ void ASTReader::loadPendingDeclChain(Decl *CanonDecl) { GlobalDeclID CanonID = CanonDecl->getGlobalID(); if (CanonID) SearchDecls.push_back(CanonDecl->getGlobalID()); // Always first. - MergedDeclsMap::iterator MergedPos = MergedDecls.find(CanonDecl); - if (MergedPos != MergedDecls.end()) - SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end()); + KeyDeclsMap::iterator KeyPos = KeyDecls.find(CanonDecl); + if (KeyPos != KeyDecls.end()) + SearchDecls.append(KeyPos->second.begin(), KeyPos->second.end()); // Build up the list of redeclarations. RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID); diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h index d1b032b27ac2..5b1c4f4963e4 100644 --- a/lib/Serialization/ASTReaderInternals.h +++ b/lib/Serialization/ASTReaderInternals.h @@ -68,8 +68,8 @@ public: return a.Kind == b.Kind && a.Data == b.Data; } - hash_value_type ComputeHash(const DeclNameKey &Key) const; - internal_key_type GetInternalKey(const external_key_type& Name) const; + static hash_value_type ComputeHash(const DeclNameKey &Key); + static internal_key_type GetInternalKey(const external_key_type& Name); static std::pair<unsigned, unsigned> ReadKeyDataLength(const unsigned char*& d); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 0d15b17c7cec..8b6863822c69 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -421,9 +421,13 @@ void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { Writer.AddTypeRef(T->getBaseType(), Record); + Record.push_back(T->getTypeArgsAsWritten().size()); + for (auto TypeArg : T->getTypeArgsAsWritten()) + Writer.AddTypeRef(TypeArg, Record); Record.push_back(T->getNumProtocols()); for (const auto *I : T->quals()) Writer.AddDeclRef(I, Record); + Record.push_back(T->isKindOfTypeAsWritten()); Code = TYPE_OBJC_OBJECT; } @@ -648,8 +652,12 @@ void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { Record.push_back(TL.hasBaseTypeAsWritten()); - Writer.AddSourceLocation(TL.getLAngleLoc(), Record); - Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + Writer.AddSourceLocation(TL.getTypeArgsLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getTypeArgsRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + Writer.AddTypeSourceInfo(TL.getTypeArgTInfo(i), Record); + Writer.AddSourceLocation(TL.getProtocolLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getProtocolRAngleLoc(), Record); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); } @@ -3626,6 +3634,55 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC, /// bitstream, or 0 if no block was written. uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC) { + // If we imported a key declaration of this namespace, write the visible + // lookup results as an update record for it rather than including them + // on this declaration. We will only look at key declarations on reload. + if (isa<NamespaceDecl>(DC) && Chain && + Chain->getKeyDeclaration(cast<Decl>(DC))->isFromASTFile()) { + // Only do this once, for the first local declaration of the namespace. + for (NamespaceDecl *Prev = cast<NamespaceDecl>(DC)->getPreviousDecl(); Prev; + Prev = Prev->getPreviousDecl()) + if (!Prev->isFromASTFile()) + return 0; + + // Note that we need to emit an update record for the primary context. + UpdatedDeclContexts.insert(DC->getPrimaryContext()); + + // Make sure all visible decls are written. They will be recorded later. We + // do this using a side data structure so we can sort the names into + // a deterministic order. + StoredDeclsMap *Map = DC->getPrimaryContext()->buildLookup(); + SmallVector<std::pair<DeclarationName, DeclContext::lookup_result>, 16> + LookupResults; + if (Map) { + LookupResults.reserve(Map->size()); + for (auto &Entry : *Map) + LookupResults.push_back( + std::make_pair(Entry.first, Entry.second.getLookupResult())); + } + + std::sort(LookupResults.begin(), LookupResults.end(), llvm::less_first()); + for (auto &NameAndResult : LookupResults) { + DeclarationName Name = NameAndResult.first; + DeclContext::lookup_result Result = NameAndResult.second; + if (Name.getNameKind() == DeclarationName::CXXConstructorName || + Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { + // We have to work around a name lookup bug here where negative lookup + // results for these names get cached in namespace lookup tables (these + // names should never be looked up in a namespace). + assert(Result.empty() && "Cannot have a constructor or conversion " + "function name in a namespace!"); + continue; + } + + for (NamedDecl *ND : Result) + if (!ND->isFromASTFile()) + GetDeclRef(ND); + } + + return 0; + } + if (DC->getPrimaryContext() != DC) return 0; @@ -3677,6 +3734,11 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { SmallString<4096> LookupTable; uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); + // If we're updating a namespace, select a key declaration as the key for the + // update record; those are the only ones that will be checked on reload. + if (isa<NamespaceDecl>(DC)) + DC = cast<DeclContext>(Chain->getKeyDeclaration(cast<Decl>(DC))); + // Write the lookup table RecordData Record; Record.push_back(UPDATE_VISIBLE); @@ -3709,11 +3771,17 @@ void ASTWriter::WriteRedeclarations() { SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap; for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) { - Decl *First = Redeclarations[I]; - assert(First->isFirstDecl() && "Not the first declaration?"); - - Decl *MostRecent = First->getMostRecentDecl(); - + const Decl *Key = Redeclarations[I]; + assert((Chain ? Chain->getKeyDeclaration(Key) == Key + : Key->isFirstDecl()) && + "not the key declaration"); + + const Decl *First = Key->getCanonicalDecl(); + const Decl *MostRecent = First->getMostRecentDecl(); + + assert((getDeclID(First) >= NUM_PREDEF_DECL_IDS || First == Key) && + "should not have imported key decls for predefined decl"); + // If we only have a single declaration, there is no point in storing // a redeclaration chain. if (First == MostRecent) @@ -3722,34 +3790,34 @@ void ASTWriter::WriteRedeclarations() { unsigned Offset = LocalRedeclChains.size(); unsigned Size = 0; LocalRedeclChains.push_back(0); // Placeholder for the size. - + // Collect the set of local redeclarations of this declaration. - for (Decl *Prev = MostRecent; Prev != First; + for (const Decl *Prev = MostRecent; Prev; Prev = Prev->getPreviousDecl()) { - if (!Prev->isFromASTFile()) { + if (!Prev->isFromASTFile() && Prev != Key) { AddDeclRef(Prev, LocalRedeclChains); ++Size; } } LocalRedeclChains[Offset] = Size; - + // Reverse the set of local redeclarations, so that we store them in // order (since we found them in reverse order). std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end()); - + // Add the mapping from the first ID from the AST to the set of local // declarations. - LocalRedeclarationsInfo Info = { getDeclID(First), Offset }; + LocalRedeclarationsInfo Info = { getDeclID(Key), Offset }; LocalRedeclsMap.push_back(Info); - + assert(N == Redeclarations.size() && "Deserialized a declaration we shouldn't have"); } - + if (LocalRedeclChains.empty()) return; - + // Sort the local redeclarations map by the first declaration ID, // since the reader will be performing binary searches on this information. llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end()); @@ -4045,25 +4113,27 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Preprocessor &PP = SemaRef.PP; // Set up predefined declaration IDs. - DeclIDs[Context.getTranslationUnitDecl()] = PREDEF_DECL_TRANSLATION_UNIT_ID; - if (Context.ObjCIdDecl) - DeclIDs[Context.ObjCIdDecl] = PREDEF_DECL_OBJC_ID_ID; - if (Context.ObjCSelDecl) - DeclIDs[Context.ObjCSelDecl] = PREDEF_DECL_OBJC_SEL_ID; - if (Context.ObjCClassDecl) - DeclIDs[Context.ObjCClassDecl] = PREDEF_DECL_OBJC_CLASS_ID; - if (Context.ObjCProtocolClassDecl) - DeclIDs[Context.ObjCProtocolClassDecl] = PREDEF_DECL_OBJC_PROTOCOL_ID; - if (Context.Int128Decl) - DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID; - if (Context.UInt128Decl) - DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID; - if (Context.ObjCInstanceTypeDecl) - DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID; - if (Context.BuiltinVaListDecl) - DeclIDs[Context.getBuiltinVaListDecl()] = PREDEF_DECL_BUILTIN_VA_LIST_ID; - if (Context.ExternCContext) - DeclIDs[Context.ExternCContext] = PREDEF_DECL_EXTERN_C_CONTEXT_ID; + auto RegisterPredefDecl = [&] (Decl *D, PredefinedDeclIDs ID) { + if (D) { + assert(D->isCanonicalDecl() && "predefined decl is not canonical"); + DeclIDs[D] = ID; + if (D->getMostRecentDecl() != D) + Redeclarations.push_back(D); + } + }; + RegisterPredefDecl(Context.getTranslationUnitDecl(), + PREDEF_DECL_TRANSLATION_UNIT_ID); + RegisterPredefDecl(Context.ObjCIdDecl, PREDEF_DECL_OBJC_ID_ID); + RegisterPredefDecl(Context.ObjCSelDecl, PREDEF_DECL_OBJC_SEL_ID); + RegisterPredefDecl(Context.ObjCClassDecl, PREDEF_DECL_OBJC_CLASS_ID); + RegisterPredefDecl(Context.ObjCProtocolClassDecl, + PREDEF_DECL_OBJC_PROTOCOL_ID); + RegisterPredefDecl(Context.Int128Decl, PREDEF_DECL_INT_128_ID); + RegisterPredefDecl(Context.UInt128Decl, PREDEF_DECL_UNSIGNED_INT_128_ID); + RegisterPredefDecl(Context.ObjCInstanceTypeDecl, + PREDEF_DECL_OBJC_INSTANCETYPE_ID); + RegisterPredefDecl(Context.BuiltinVaListDecl, PREDEF_DECL_BUILTIN_VA_LIST_ID); + RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID); // Build a record containing all of the tentative definitions in this file, in // TentativeDefinitions order. Generally, this record will be empty for @@ -5667,7 +5737,7 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) { assert(!DoneWritingDeclsAndTypes && "Already done writing updates!"); if (!Chain) return; - Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) { + Chain->forEachImportedKeyDecl(FD, [&](const Decl *D) { // If we don't already know the exception specification for this redecl // chain, add an update record for it. if (isUnresolvedExceptionSpec(cast<FunctionDecl>(D) @@ -5681,7 +5751,7 @@ void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) { void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) { assert(!WritingAST && "Already writing the AST!"); if (!Chain) return; - Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) { + Chain->forEachImportedKeyDecl(FD, [&](const Decl *D) { DeclUpdates[D].push_back( DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType)); }); @@ -5692,7 +5762,7 @@ void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD, assert(!WritingAST && "Already writing the AST!"); assert(Delete && "Not given an operator delete"); if (!Chain) return; - Chain->forEachFormerlyCanonicalImportedDecl(DD, [&](const Decl *D) { + Chain->forEachImportedKeyDecl(DD, [&](const Decl *D) { DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete)); }); } diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 6c5bc5bbd483..fd6708dd5c3f 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -117,6 +117,7 @@ namespace clang { // FIXME: Put in the same order is DeclNodes.td? void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *D); void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); void VisitObjCIvarDecl(ObjCIvarDecl *D); @@ -131,6 +132,22 @@ namespace clang { void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + /// Add an Objective-C type parameter list to the given record. + void AddObjCTypeParamList(ObjCTypeParamList *typeParams) { + // Empty type parameter list. + if (!typeParams) { + Record.push_back(0); + return; + } + + Record.push_back(typeParams->size()); + for (auto typeParam : *typeParams) { + Writer.AddDeclRef(typeParam, Record); + } + Writer.AddSourceLocation(typeParams->getLAngleLoc(), Record); + Writer.AddSourceLocation(typeParams->getRAngleLoc(), Record); + } + void AddFunctionDefinition(const FunctionDecl *FD) { assert(FD->doesThisDeclarationHaveABody()); if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { @@ -237,6 +254,8 @@ void ASTDeclWriter::VisitDecl(Decl *D) { // // This happens when we instantiate a class with a friend declaration or a // function with a local extern declaration, for instance. + // + // FIXME: Can we handle this in AddedVisibleDecl instead? if (D->isOutOfLine()) { auto *DC = D->getDeclContext(); while (auto *NS = dyn_cast<NamespaceDecl>(DC->getRedeclContext())) { @@ -562,6 +581,16 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { Code = serialization::DECL_OBJC_METHOD; } +void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { + VisitTypedefNameDecl(D); + Record.push_back(D->Variance); + Record.push_back(D->Index); + Writer.AddSourceLocation(D->VarianceLoc, Record); + Writer.AddSourceLocation(D->ColonLoc, Record); + + Code = serialization::DECL_OBJC_TYPE_PARAM; +} + void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getAtStartLoc(), Record); @@ -573,14 +602,14 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { VisitRedeclarable(D); VisitObjCContainerDecl(D); Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); + AddObjCTypeParamList(D->TypeParamList); Record.push_back(D->isThisDeclarationADefinition()); if (D->isThisDeclarationADefinition()) { // Write the DefinitionData ObjCInterfaceDecl::DefinitionData &Data = D->data(); - Writer.AddDeclRef(D->getSuperClass(), Record); - Writer.AddSourceLocation(D->getSuperClassLoc(), Record); + Writer.AddTypeSourceInfo(D->getSuperClassTInfo(), Record); Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record); Record.push_back(Data.HasDesignatedInitializers); @@ -660,6 +689,7 @@ void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); Writer.AddDeclRef(D->getClassInterface(), Record); + AddObjCTypeParamList(D->TypeParamList); Record.push_back(D->protocol_size()); for (const auto *I : D->protocols()) Writer.AddDeclRef(I, Record); @@ -977,40 +1007,6 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { Writer.AddDeclRef(D->getAnonymousNamespace(), Record); Code = serialization::DECL_NAMESPACE; - if (Writer.hasChain() && !D->isOriginalNamespace() && - D->getOriginalNamespace()->isFromASTFile()) { - NamespaceDecl *NS = D->getOriginalNamespace(); - Writer.UpdatedDeclContexts.insert(NS); - - // Make sure all visible decls are written. They will be recorded later. We - // do this using a side data structure so we can sort the names into - // a deterministic order. - StoredDeclsMap *Map = NS->buildLookup(); - SmallVector<std::pair<DeclarationName, DeclContext::lookup_result>, 16> - LookupResults; - LookupResults.reserve(Map->size()); - for (auto &Entry : *Map) - LookupResults.push_back( - std::make_pair(Entry.first, Entry.second.getLookupResult())); - - std::sort(LookupResults.begin(), LookupResults.end(), llvm::less_first()); - for (auto &NameAndResult : LookupResults) { - DeclarationName Name = NameAndResult.first; - DeclContext::lookup_result Result = NameAndResult.second; - if (Name.getNameKind() == DeclarationName::CXXConstructorName || - Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { - // We have to work around a name lookup bug here where negative lookup - // results for these names get cached in namespace lookup tables. - assert(Result.empty() && "Cannot have a constructor or conversion " - "function name in a namespace!"); - continue; - } - - for (NamedDecl *ND : Result) - Writer.GetDeclRef(ND); - } - } - if (Writer.hasChain() && D->isAnonymousNamespace() && D == D->getMostRecentDecl()) { // This is a most recent reopening of the anonymous namespace. If its parent @@ -1482,6 +1478,17 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, Record.push_back(VisibleOffset); } +/// Determine whether D is the first declaration in its redeclaration chain that +/// is not from an AST file. +template <typename T> +static bool isFirstLocalDecl(Redeclarable<T> *D) { + assert(D && !static_cast<T*>(D)->isFromASTFile()); + do + D = D->getPreviousDecl(); + while (D && static_cast<T*>(D)->isFromASTFile()); + return !D; +} + template <typename T> void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { T *First = D->getFirstDecl(); @@ -1490,41 +1497,30 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) && "Not considered redeclarable?"); - // There is more than one declaration of this entity, so we will need to - // write a redeclaration chain. Writer.AddDeclRef(First, Record); - Writer.Redeclarations.insert(First); - auto *Previous = D->getPreviousDecl(); - - // In a modules build, we can have imported declarations after a local - // canonical declaration. If this is the first local declaration, emit - // a list of all such imported declarations so that we can ensure they - // are loaded before we are. This allows us to rebuild the redecl chain - // in the right order on reload (all declarations imported by a module - // should be before all declarations provided by that module). - bool EmitImportedMergedCanonicalDecls = false; + // In a modules build, emit a list of all imported key declarations + // (excluding First, if it was imported), so that we can be sure that all + // redeclarations visible to this module are before D in the redecl chain. + unsigned I = Record.size(); + Record.push_back(0); if (Context.getLangOpts().Modules && Writer.Chain) { - auto *PreviousLocal = Previous; - while (PreviousLocal && PreviousLocal->isFromASTFile()) - PreviousLocal = PreviousLocal->getPreviousDecl(); - if (!PreviousLocal) - EmitImportedMergedCanonicalDecls = true; + if (isFirstLocalDecl(D)) { + Writer.Chain->forEachImportedKeyDecl(First, [&](const Decl *D) { + if (D != First) + Writer.AddDeclRef(D, Record); + }); + Record[I] = Record.size() - I - 1; + + // Write a redeclaration chain, attached to the first key decl. + Writer.Redeclarations.push_back(Writer.Chain->getKeyDeclaration(First)); + } + } else if (D == First || D->getPreviousDecl()->isFromASTFile()) { + assert(isFirstLocalDecl(D) && "imported decl after local decl"); + + // Write a redeclaration chain attached to the first decl. + Writer.Redeclarations.push_back(First); } - if (EmitImportedMergedCanonicalDecls) { - llvm::SmallMapVector<ModuleFile*, Decl*, 16> FirstInModule; - for (auto *Redecl = MostRecent; Redecl; - Redecl = Redecl->getPreviousDecl()) - if (Redecl->isFromASTFile()) - FirstInModule[Writer.Chain->getOwningModuleFile(Redecl)] = Redecl; - // FIXME: If FirstInModule has entries for modules A and B, and B imports - // A (directly or indirectly), we don't need to write the entry for A. - Record.push_back(FirstInModule.size()); - for (auto I = FirstInModule.rbegin(), E = FirstInModule.rend(); - I != E; ++I) - Writer.AddDeclRef(I->second, Record); - } else - Record.push_back(0); // Make sure that we serialize both the previous and the most-recent // declarations, which (transitively) ensures that all declarations in the @@ -1532,7 +1528,7 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { // // FIXME: This is not correct; when we reach an imported declaration we // won't emit its previous declaration. - (void)Writer.GetDeclRef(Previous); + (void)Writer.GetDeclRef(D->getPreviousDecl()); (void)Writer.GetDeclRef(MostRecent); } else { // We use the sentinel value 0 to indicate an only declaration. diff --git a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp index a2cf8e10d09b..016cb146f84e 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp @@ -34,7 +34,6 @@ struct SelectorDescriptor { const char *SelectorName; unsigned ArgumentCount; }; -} //===----------------------------------------------------------------------===// // FindSuperCallVisitor - Identify specific calls to the superclass. @@ -63,7 +62,6 @@ private: // ObjCSuperCallChecker //===----------------------------------------------------------------------===// -namespace { class ObjCSuperCallChecker : public Checker< check::ASTDecl<ObjCImplementationDecl> > { public: diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp index b64e30b31007..6ba64f52d183 100644 --- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp +++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp @@ -8,7 +8,10 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/CheckerRegistry.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/raw_ostream.h" @@ -111,6 +114,28 @@ void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, } } +void CheckerRegistry::validateCheckerOptions(const AnalyzerOptions &opts, + DiagnosticsEngine &diags) const { + for (auto &config : opts.Config) { + size_t pos = config.getKey().find(':'); + if (pos == StringRef::npos) + continue; + + bool hasChecker = false; + StringRef checkerName = config.getKey().substr(0, pos); + for (auto &checker : Checkers) { + if (checker.FullName.startswith(checkerName) && + (checker.FullName.size() == pos || checker.FullName[pos] == '.')) { + hasChecker = true; + break; + } + } + if (!hasChecker) { + diags.Report(diag::err_unknown_analyzer_checker) << checkerName; + } + } +} + void CheckerRegistry::printHelp(raw_ostream &out, size_t maxNameChars) const { // FIXME: Alphabetical sort puts 'experimental' in the middle. diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index 1fa675433b56..5ac845825c8d 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -824,9 +824,12 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, QualType T; if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) T = TSI->getType(); - else - T = getContext().getFunctionNoProtoType(getContext().VoidTy); - + if (T.isNull()) + T = getContext().VoidTy; + if (!T->getAs<FunctionType>()) + T = getContext().getFunctionNoProtoType(T); + T = getContext().getBlockPointerType(T); + const BlockTextRegion *BTR = getBlockTextRegion(BD, C.getCanonicalType(T), STC->getAnalysisDeclContext()); diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index b3ff79750b49..7fced1e5c71a 100644 --- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -114,6 +114,7 @@ ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, ClangCheckerRegistry allCheckers(plugins, &diags); allCheckers.initializeManager(*checkerMgr, checkerOpts); + allCheckers.validateCheckerOptions(opts, diags); checkerMgr->finishedCheckerRegistration(); for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) { |