diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-01-27 22:06:42 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-01-27 22:06:42 +0000 |
| commit | 6f8fc217eaa12bf657be1c6468ed9938d10168b3 (patch) | |
| tree | a1fd89b864d9b93e2ad68fe1dcf7afee2e3c8d76 /clang/lib | |
| parent | 77fc4c146f0870ffb09c1afb823ccbe742c5e6ff (diff) | |
Diffstat (limited to 'clang/lib')
276 files changed, 7998 insertions, 3983 deletions
diff --git a/clang/lib/ARCMigrate/Internals.h b/clang/lib/ARCMigrate/Internals.h index ed0136e4867a..8b482738cc89 100644 --- a/clang/lib/ARCMigrate/Internals.h +++ b/clang/lib/ARCMigrate/Internals.h @@ -154,13 +154,11 @@ public: std::vector<SourceLocation> &ARCMTMacroLocs; Optional<bool> EnableCFBridgeFns; - MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode, - Sema &sema, TransformActions &TA, - const CapturedDiagList &capturedDiags, + MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode, Sema &sema, + TransformActions &TA, const CapturedDiagList &capturedDiags, std::vector<SourceLocation> &ARCMTMacroLocs) - : Ctx(Ctx), OrigGCMode(OrigGCMode), MigOptions(), - SemaRef(sema), TA(TA), CapturedDiags(capturedDiags), - ARCMTMacroLocs(ARCMTMacroLocs) { } + : Ctx(Ctx), OrigGCMode(OrigGCMode), SemaRef(sema), TA(TA), + CapturedDiags(capturedDiags), ARCMTMacroLocs(ARCMTMacroLocs) {} const CapturedDiagList &getDiags() const { return CapturedDiags; } diff --git a/clang/lib/ARCMigrate/TransAutoreleasePool.cpp b/clang/lib/ARCMigrate/TransAutoreleasePool.cpp index 393adcd85a3f..47587d81850a 100644 --- a/clang/lib/ARCMigrate/TransAutoreleasePool.cpp +++ b/clang/lib/ARCMigrate/TransAutoreleasePool.cpp @@ -229,8 +229,9 @@ private: bool IsFollowedBySimpleReturnStmt; SmallVector<ObjCMessageExpr *, 4> Releases; - PoolScope() : PoolVar(nullptr), CompoundParent(nullptr), Begin(), End(), - IsFollowedBySimpleReturnStmt(false) { } + PoolScope() + : PoolVar(nullptr), CompoundParent(nullptr), + IsFollowedBySimpleReturnStmt(false) {} SourceRange getIndentedRange() const { Stmt::child_iterator rangeS = Begin; diff --git a/clang/lib/ARCMigrate/Transforms.cpp b/clang/lib/ARCMigrate/Transforms.cpp index ca48160d9c85..a08b0d084bb6 100644 --- a/clang/lib/ARCMigrate/Transforms.cpp +++ b/clang/lib/ARCMigrate/Transforms.cpp @@ -417,7 +417,7 @@ bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr, if (tok.is(tok::r_paren)) return false; - while (1) { + while (true) { if (tok.isNot(tok::raw_identifier)) return false; if (tok.getRawIdentifier() == fromAttr) { if (!toAttr.empty()) { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 008b703d4c1a..8a780250b6d8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6147,6 +6147,376 @@ bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) { return X.getAsVoidPointer() == Y.getAsVoidPointer(); } +bool ASTContext::isSameTemplateParameter(NamedDecl *X, NamedDecl *Y) { + if (X->getKind() != Y->getKind()) + return false; + + if (auto *TX = dyn_cast<TemplateTypeParmDecl>(X)) { + auto *TY = cast<TemplateTypeParmDecl>(Y); + if (TX->isParameterPack() != TY->isParameterPack()) + return false; + if (TX->hasTypeConstraint() != TY->hasTypeConstraint()) + return false; + const TypeConstraint *TXTC = TX->getTypeConstraint(); + const TypeConstraint *TYTC = TY->getTypeConstraint(); + if (!TXTC != !TYTC) + return false; + if (TXTC && TYTC) { + auto *NCX = TXTC->getNamedConcept(); + auto *NCY = TYTC->getNamedConcept(); + if (!NCX || !NCY || !isSameEntity(NCX, NCY)) + return false; + if (TXTC->hasExplicitTemplateArgs() != TYTC->hasExplicitTemplateArgs()) + return false; + if (TXTC->hasExplicitTemplateArgs()) { + auto *TXTCArgs = TXTC->getTemplateArgsAsWritten(); + auto *TYTCArgs = TYTC->getTemplateArgsAsWritten(); + if (TXTCArgs->NumTemplateArgs != TYTCArgs->NumTemplateArgs) + return false; + llvm::FoldingSetNodeID XID, YID; + for (auto &ArgLoc : TXTCArgs->arguments()) + ArgLoc.getArgument().Profile(XID, X->getASTContext()); + for (auto &ArgLoc : TYTCArgs->arguments()) + ArgLoc.getArgument().Profile(YID, Y->getASTContext()); + if (XID != YID) + return false; + } + } + return true; + } + + if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) { + auto *TY = cast<NonTypeTemplateParmDecl>(Y); + return TX->isParameterPack() == TY->isParameterPack() && + TX->getASTContext().hasSameType(TX->getType(), TY->getType()); + } + + auto *TX = cast<TemplateTemplateParmDecl>(X); + auto *TY = cast<TemplateTemplateParmDecl>(Y); + return TX->isParameterPack() == TY->isParameterPack() && + isSameTemplateParameterList(TX->getTemplateParameters(), + TY->getTemplateParameters()); +} + +bool ASTContext::isSameTemplateParameterList(TemplateParameterList *X, + TemplateParameterList *Y) { + if (X->size() != Y->size()) + return false; + + for (unsigned I = 0, N = X->size(); I != N; ++I) + if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I))) + return false; + + const Expr *XRC = X->getRequiresClause(); + const Expr *YRC = Y->getRequiresClause(); + if (!XRC != !YRC) + return false; + if (XRC) { + llvm::FoldingSetNodeID XRCID, YRCID; + XRC->Profile(XRCID, *this, /*Canonical=*/true); + YRC->Profile(YRCID, *this, /*Canonical=*/true); + if (XRCID != YRCID) + return false; + } + + return true; +} + +static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) { + if (auto *NS = X->getAsNamespace()) + return NS; + if (auto *NAS = X->getAsNamespaceAlias()) + return NAS->getNamespace(); + return nullptr; +} + +static bool isSameQualifier(const NestedNameSpecifier *X, + const NestedNameSpecifier *Y) { + if (auto *NSX = getNamespace(X)) { + auto *NSY = getNamespace(Y); + if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl()) + return false; + } else if (X->getKind() != Y->getKind()) + return false; + + // FIXME: For namespaces and types, we're permitted to check that the entity + // is named via the same tokens. We should probably do so. + switch (X->getKind()) { + case NestedNameSpecifier::Identifier: + if (X->getAsIdentifier() != Y->getAsIdentifier()) + return false; + break; + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + // We've already checked that we named the same namespace. + break; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + if (X->getAsType()->getCanonicalTypeInternal() != + Y->getAsType()->getCanonicalTypeInternal()) + return false; + break; + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: + return true; + } + + // Recurse into earlier portion of NNS, if any. + auto *PX = X->getPrefix(); + auto *PY = Y->getPrefix(); + if (PX && PY) + return isSameQualifier(PX, PY); + return !PX && !PY; +} + +/// Determine whether the attributes we can overload on are identical for A and +/// B. Will ignore any overloadable attrs represented in the type of A and B. +static bool hasSameOverloadableAttrs(const FunctionDecl *A, + const FunctionDecl *B) { + // Note that pass_object_size attributes are represented in the function's + // ExtParameterInfo, so we don't need to check them here. + + llvm::FoldingSetNodeID Cand1ID, Cand2ID; + auto AEnableIfAttrs = A->specific_attrs<EnableIfAttr>(); + auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>(); + + for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) { + Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair); + Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair); + + // Return false if the number of enable_if attributes is different. + if (!Cand1A || !Cand2A) + return false; + + Cand1ID.clear(); + Cand2ID.clear(); + + (*Cand1A)->getCond()->Profile(Cand1ID, A->getASTContext(), true); + (*Cand2A)->getCond()->Profile(Cand2ID, B->getASTContext(), true); + + // Return false if any of the enable_if expressions of A and B are + // different. + if (Cand1ID != Cand2ID) + return false; + } + return true; +} + +bool ASTContext::isSameEntity(NamedDecl *X, NamedDecl *Y) { + if (X == Y) + return true; + + if (X->getDeclName() != Y->getDeclName()) + return false; + + // Must be in the same context. + // + // Note that we can't use DeclContext::Equals here, because the DeclContexts + // could be two different declarations of the same function. (We will fix the + // semantic DC to refer to the primary definition after merging.) + if (!declaresSameEntity(cast<Decl>(X->getDeclContext()->getRedeclContext()), + cast<Decl>(Y->getDeclContext()->getRedeclContext()))) + return false; + + // Two typedefs refer to the same entity if they have the same underlying + // type. + if (const auto *TypedefX = dyn_cast<TypedefNameDecl>(X)) + if (const auto *TypedefY = dyn_cast<TypedefNameDecl>(Y)) + return hasSameType(TypedefX->getUnderlyingType(), + TypedefY->getUnderlyingType()); + + // Must have the same kind. + if (X->getKind() != Y->getKind()) + return false; + + // Objective-C classes and protocols with the same name always match. + if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X)) + return true; + + if (isa<ClassTemplateSpecializationDecl>(X)) { + // No need to handle these here: we merge them when adding them to the + // template. + return false; + } + + // Compatible tags match. + if (const auto *TagX = dyn_cast<TagDecl>(X)) { + const auto *TagY = cast<TagDecl>(Y); + return (TagX->getTagKind() == TagY->getTagKind()) || + ((TagX->getTagKind() == TTK_Struct || + TagX->getTagKind() == TTK_Class || + TagX->getTagKind() == TTK_Interface) && + (TagY->getTagKind() == TTK_Struct || + TagY->getTagKind() == TTK_Class || + TagY->getTagKind() == TTK_Interface)); + } + + // Functions with the same type and linkage match. + // FIXME: This needs to cope with merging of prototyped/non-prototyped + // functions, etc. + if (const auto *FuncX = dyn_cast<FunctionDecl>(X)) { + const auto *FuncY = cast<FunctionDecl>(Y); + if (const auto *CtorX = dyn_cast<CXXConstructorDecl>(X)) { + const auto *CtorY = cast<CXXConstructorDecl>(Y); + if (CtorX->getInheritedConstructor() && + !isSameEntity(CtorX->getInheritedConstructor().getConstructor(), + CtorY->getInheritedConstructor().getConstructor())) + return false; + } + + if (FuncX->isMultiVersion() != FuncY->isMultiVersion()) + return false; + + // Multiversioned functions with different feature strings are represented + // as separate declarations. + if (FuncX->isMultiVersion()) { + const auto *TAX = FuncX->getAttr<TargetAttr>(); + const auto *TAY = FuncY->getAttr<TargetAttr>(); + assert(TAX && TAY && "Multiversion Function without target attribute"); + + if (TAX->getFeaturesStr() != TAY->getFeaturesStr()) + return false; + } + + const Expr *XRC = FuncX->getTrailingRequiresClause(); + const Expr *YRC = FuncY->getTrailingRequiresClause(); + if (!XRC != !YRC) + return false; + if (XRC) { + llvm::FoldingSetNodeID XRCID, YRCID; + XRC->Profile(XRCID, *this, /*Canonical=*/true); + YRC->Profile(YRCID, *this, /*Canonical=*/true); + if (XRCID != YRCID) + return false; + } + + auto GetTypeAsWritten = [](const FunctionDecl *FD) { + // Map to the first declaration that we've already merged into this one. + // The TSI of redeclarations might not match (due to calling conventions + // being inherited onto the type but not the TSI), but the TSI type of + // the first declaration of the function should match across modules. + FD = FD->getCanonicalDecl(); + return FD->getTypeSourceInfo() ? FD->getTypeSourceInfo()->getType() + : FD->getType(); + }; + QualType XT = GetTypeAsWritten(FuncX), YT = GetTypeAsWritten(FuncY); + if (!hasSameType(XT, YT)) { + // We can get functions with different types on the redecl chain in C++17 + // if they have differing exception specifications and at least one of + // the excpetion specs is unresolved. + auto *XFPT = XT->getAs<FunctionProtoType>(); + auto *YFPT = YT->getAs<FunctionProtoType>(); + if (getLangOpts().CPlusPlus17 && XFPT && YFPT && + (isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) || + isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) && + hasSameFunctionTypeIgnoringExceptionSpec(XT, YT)) + return true; + return false; + } + + return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() && + hasSameOverloadableAttrs(FuncX, FuncY); + } + + // Variables with the same type and linkage match. + if (const auto *VarX = dyn_cast<VarDecl>(X)) { + const auto *VarY = cast<VarDecl>(Y); + if (VarX->getLinkageInternal() == VarY->getLinkageInternal()) { + if (hasSameType(VarX->getType(), VarY->getType())) + return true; + + // We can get decls with different types on the redecl chain. Eg. + // template <typename T> struct S { static T Var[]; }; // #1 + // template <typename T> T S<T>::Var[sizeof(T)]; // #2 + // Only? happens when completing an incomplete array type. In this case + // when comparing #1 and #2 we should go through their element type. + const ArrayType *VarXTy = getAsArrayType(VarX->getType()); + const ArrayType *VarYTy = getAsArrayType(VarY->getType()); + if (!VarXTy || !VarYTy) + return false; + if (VarXTy->isIncompleteArrayType() || VarYTy->isIncompleteArrayType()) + return hasSameType(VarXTy->getElementType(), VarYTy->getElementType()); + } + return false; + } + + // Namespaces with the same name and inlinedness match. + if (const auto *NamespaceX = dyn_cast<NamespaceDecl>(X)) { + const auto *NamespaceY = cast<NamespaceDecl>(Y); + return NamespaceX->isInline() == NamespaceY->isInline(); + } + + // Identical template names and kinds match if their template parameter lists + // and patterns match. + if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) { + const auto *TemplateY = cast<TemplateDecl>(Y); + return isSameEntity(TemplateX->getTemplatedDecl(), + TemplateY->getTemplatedDecl()) && + isSameTemplateParameterList(TemplateX->getTemplateParameters(), + TemplateY->getTemplateParameters()); + } + + // Fields with the same name and the same type match. + if (const auto *FDX = dyn_cast<FieldDecl>(X)) { + const auto *FDY = cast<FieldDecl>(Y); + // FIXME: Also check the bitwidth is odr-equivalent, if any. + return hasSameType(FDX->getType(), FDY->getType()); + } + + // Indirect fields with the same target field match. + if (const auto *IFDX = dyn_cast<IndirectFieldDecl>(X)) { + const auto *IFDY = cast<IndirectFieldDecl>(Y); + return IFDX->getAnonField()->getCanonicalDecl() == + IFDY->getAnonField()->getCanonicalDecl(); + } + + // Enumerators with the same name match. + if (isa<EnumConstantDecl>(X)) + // FIXME: Also check the value is odr-equivalent. + return true; + + // Using shadow declarations with the same target match. + if (const auto *USX = dyn_cast<UsingShadowDecl>(X)) { + const auto *USY = cast<UsingShadowDecl>(Y); + return USX->getTargetDecl() == USY->getTargetDecl(); + } + + // Using declarations with the same qualifier match. (We already know that + // the name matches.) + if (const auto *UX = dyn_cast<UsingDecl>(X)) { + const auto *UY = cast<UsingDecl>(Y); + return isSameQualifier(UX->getQualifier(), UY->getQualifier()) && + UX->hasTypename() == UY->hasTypename() && + UX->isAccessDeclaration() == UY->isAccessDeclaration(); + } + if (const auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) { + const auto *UY = cast<UnresolvedUsingValueDecl>(Y); + return isSameQualifier(UX->getQualifier(), UY->getQualifier()) && + UX->isAccessDeclaration() == UY->isAccessDeclaration(); + } + if (const auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X)) { + return isSameQualifier( + UX->getQualifier(), + cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier()); + } + + // Using-pack declarations are only created by instantiation, and match if + // they're instantiated from matching UnresolvedUsing...Decls. + if (const auto *UX = dyn_cast<UsingPackDecl>(X)) { + return declaresSameEntity( + UX->getInstantiatedFromUsingDecl(), + cast<UsingPackDecl>(Y)->getInstantiatedFromUsingDecl()); + } + + // Namespace alias definitions with the same target match. + if (const auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) { + const auto *NAY = cast<NamespaceAliasDecl>(Y); + return NAX->getNamespace()->Equals(NAY->getNamespace()); + } + + return false; +} + TemplateArgument ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { switch (Arg.getKind()) { @@ -8476,8 +8846,8 @@ static TypedefDecl *CreateHexagonBuiltinVaListDecl(const ASTContext *Context) { FieldDecl *Field = FieldDecl::Create( const_cast<ASTContext &>(*Context), VaListTagDecl, SourceLocation(), SourceLocation(), &Context->Idents.get(FieldNames[i]), FieldTypes[i], - /*TInfo=*/0, - /*BitWidth=*/0, + /*TInfo=*/nullptr, + /*BitWidth=*/nullptr, /*Mutable=*/false, ICIS_NoInit); Field->setAccess(AS_public); VaListTagDecl->addDecl(Field); @@ -9819,12 +10189,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, // designates the object or function denoted by the reference, and the // expression is an lvalue unless the reference is an rvalue reference and // the expression is a function call (possibly inside parentheses). - if (LangOpts.OpenMP && LHS->getAs<ReferenceType>() && - RHS->getAs<ReferenceType>() && LHS->getTypeClass() == RHS->getTypeClass()) - return mergeTypes(LHS->getAs<ReferenceType>()->getPointeeType(), - RHS->getAs<ReferenceType>()->getPointeeType(), + auto *LHSRefTy = LHS->getAs<ReferenceType>(); + auto *RHSRefTy = RHS->getAs<ReferenceType>(); + if (LangOpts.OpenMP && LHSRefTy && RHSRefTy && + LHS->getTypeClass() == RHS->getTypeClass()) + return mergeTypes(LHSRefTy->getPointeeType(), RHSRefTy->getPointeeType(), OfBlockPointer, Unqualified, BlockReturnType); - if (LHS->getAs<ReferenceType>() || RHS->getAs<ReferenceType>()) + if (LHSRefTy || RHSRefTy) return {}; if (Unqualified) { @@ -10311,7 +10682,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { // For _BitInt, return an unsigned _BitInt with same width. if (const auto *EITy = T->getAs<BitIntType>()) - return getBitIntType(/*IsUnsigned=*/true, EITy->getNumBits()); + return getBitIntType(/*Unsigned=*/true, EITy->getNumBits()); // For enums, get the underlying integer type of the enum, and let the general // integer type signchanging code handle it. @@ -10379,7 +10750,7 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const { // For _BitInt, return a signed _BitInt with same width. if (const auto *EITy = T->getAs<BitIntType>()) - return getBitIntType(/*IsUnsigned=*/false, EITy->getNumBits()); + return getBitIntType(/*Unsigned=*/false, EITy->getNumBits()); // For enums, get the underlying integer type of the enum, and let the general // integer type signchanging code handle it. @@ -11574,6 +11945,15 @@ uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const { return getTargetInfo().getNullPointerValue(AS); } +unsigned ASTContext::getTargetAddressSpace(QualType T) const { + return T->isFunctionType() ? getTargetInfo().getProgramAddressSpace() + : getTargetAddressSpace(T.getQualifiers()); +} + +unsigned ASTContext::getTargetAddressSpace(Qualifiers Q) const { + return getTargetAddressSpace(Q.getAddressSpace()); +} + unsigned ASTContext::getTargetAddressSpace(LangAS AS) const { if (isTargetAddressSpace(AS)) return toTargetAddressSpace(AS); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 7f78da10e0b3..457465e87d93 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -8409,8 +8409,8 @@ Expected<TypeSourceInfo *> ASTImporter::Import(TypeSourceInfo *FromTSI) { // and destructed after it is created. The construction already performs the // import of the data. template <typename T> struct AttrArgImporter { - AttrArgImporter<T>(const AttrArgImporter<T> &) = delete; - AttrArgImporter<T>(AttrArgImporter<T> &&) = default; + AttrArgImporter(const AttrArgImporter<T> &) = delete; + AttrArgImporter(AttrArgImporter<T> &&) = default; AttrArgImporter<T> &operator=(const AttrArgImporter<T> &) = delete; AttrArgImporter<T> &operator=(AttrArgImporter<T> &&) = default; @@ -8429,8 +8429,8 @@ private: // is used by the attribute classes. This object should be created once for the // array data to be imported (the array size is not imported, just copied). template <typename T> struct AttrArgArrayImporter { - AttrArgArrayImporter<T>(const AttrArgArrayImporter<T> &) = delete; - AttrArgArrayImporter<T>(AttrArgArrayImporter<T> &&) = default; + AttrArgArrayImporter(const AttrArgArrayImporter<T> &) = delete; + AttrArgArrayImporter(AttrArgArrayImporter<T> &&) = default; AttrArgArrayImporter<T> &operator=(const AttrArgArrayImporter<T> &) = delete; AttrArgArrayImporter<T> &operator=(AttrArgArrayImporter<T> &&) = default; diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index c2f13cf63830..7b8acfcd92be 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -139,6 +139,13 @@ void OMPDeclareTargetDeclAttr::printPrettyPragma( OS << " device_type(" << ConvertDevTypeTyToStr(getDevType()) << ")"; if (getMapType() != MT_To) OS << ' ' << ConvertMapTypeTyToStr(getMapType()); + if (Expr *E = getIndirectExpr()) { + OS << " indirect("; + E->printPretty(OS, nullptr, Policy); + OS << ")"; + } else if (getIndirect()) { + OS << " indirect"; + } } llvm::Optional<OMPDeclareTargetDeclAttr *> diff --git a/clang/lib/AST/CXXABI.h b/clang/lib/AST/CXXABI.h index ca9424bcb7a4..9258a53fefeb 100644 --- a/clang/lib/AST/CXXABI.h +++ b/clang/lib/AST/CXXABI.h @@ -21,7 +21,6 @@ namespace clang { class ASTContext; class CXXConstructorDecl; class DeclaratorDecl; -class Expr; class MangleContext; class MangleNumberingContext; class MemberPointerType; diff --git a/clang/lib/AST/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp index 93531c06192d..61ce8979f13f 100644 --- a/clang/lib/AST/CommentLexer.cpp +++ b/clang/lib/AST/CommentLexer.cpp @@ -94,31 +94,12 @@ void Lexer::skipLineStartingDecorations() { if (BufferPtr == CommentEnd) return; - switch (*BufferPtr) { - case ' ': - case '\t': - case '\f': - case '\v': { - const char *NewBufferPtr = BufferPtr; - NewBufferPtr++; - if (NewBufferPtr == CommentEnd) + const char *NewBufferPtr = BufferPtr; + while (isHorizontalWhitespace(*NewBufferPtr)) + if (++NewBufferPtr == CommentEnd) return; - - char C = *NewBufferPtr; - while (isHorizontalWhitespace(C)) { - NewBufferPtr++; - if (NewBufferPtr == CommentEnd) - return; - C = *NewBufferPtr; - } - if (C == '*') - BufferPtr = NewBufferPtr + 1; - break; - } - case '*': - BufferPtr++; - break; - } + if (*NewBufferPtr == '*') + BufferPtr = NewBufferPtr + 1; } namespace { @@ -289,6 +270,29 @@ void Lexer::formTokenWithChars(Token &Result, const char *TokEnd, BufferPtr = TokEnd; } +const char *Lexer::skipTextToken() { + const char *TokenPtr = BufferPtr; + assert(TokenPtr < CommentEnd); + StringRef TokStartSymbols = ParseCommands ? "\n\r\\@\"&<" : "\n\r"; + +again: + size_t End = + StringRef(TokenPtr, CommentEnd - TokenPtr).find_first_of(TokStartSymbols); + if (End == StringRef::npos) + return CommentEnd; + + // Doxygen doesn't recognize any commands in a one-line double quotation. + // If we don't find an ending quotation mark, we pretend it never began. + if (*(TokenPtr + End) == '\"') { + TokenPtr += End + 1; + End = StringRef(TokenPtr, CommentEnd - TokenPtr).find_first_of("\n\r\""); + if (End != StringRef::npos && *(TokenPtr + End) == '\"') + TokenPtr += End + 1; + goto again; + } + return TokenPtr + End; +} + void Lexer::lexCommentText(Token &T) { assert(CommentState == LCS_InsideBCPLComment || CommentState == LCS_InsideCComment); @@ -309,17 +313,8 @@ void Lexer::lexCommentText(Token &T) { skipLineStartingDecorations(); return; - default: { - StringRef TokStartSymbols = ParseCommands ? "\n\r\\@&<" : "\n\r"; - size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr) - .find_first_of(TokStartSymbols); - if (End != StringRef::npos) - TokenPtr += End; - else - TokenPtr = CommentEnd; - formTextToken(T, TokenPtr); - return; - } + default: + return formTextToken(T, skipTextToken()); } }; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index e63560f1b6fe..b2ee34f20cf7 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -786,6 +786,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // // Note that we don't want to make the variable non-external // because of this, but unique-external linkage suits us. + if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var) && !IgnoreVarTypeLinkage) { LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); @@ -912,10 +913,6 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, if (!isExternallyVisible(LV.getLinkage())) return LinkageInfo(LV.getLinkage(), DefaultVisibility, false); - // Mark the symbols as hidden when compiling for the device. - if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice) - LV.mergeVisibility(HiddenVisibility, /*newExplicit=*/false); - return LV; } @@ -1069,6 +1066,7 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, // Finally, merge in information from the class. LV.mergeMaybeWithVisibility(classLV, considerClassVisibility); + return LV; } @@ -3251,7 +3249,6 @@ bool FunctionDecl::isGlobal() const { if (const auto *Namespace = cast<NamespaceDecl>(DC)) { if (!Namespace->getDeclName()) return false; - break; } } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 064012ba865c..9ee1cc083086 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -995,6 +995,15 @@ bool Decl::AccessDeclContextCheck() const { return true; } +bool Decl::isInExportDeclContext() const { + const DeclContext *DC = getLexicalDeclContext(); + + while (DC && !isa<ExportDecl>(DC)) + DC = DC->getLexicalParent(); + + return DC && isa<ExportDecl>(DC); +} + static Decl::Kind getKind(const Decl *D) { return D->getKind(); } static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); } @@ -1212,7 +1221,8 @@ bool DeclContext::Encloses(const DeclContext *DC) const { return getPrimaryContext()->Encloses(DC); for (; DC; DC = DC->getParent()) - if (!isa<LinkageSpecDecl>(DC) && DC->getPrimaryContext() == this) + if (!isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC) && + DC->getPrimaryContext() == this) return true; return false; } @@ -1643,9 +1653,9 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) { DeclContext::lookup_result DeclContext::lookup(DeclarationName Name) const { - assert(getDeclKind() != Decl::LinkageSpec && - getDeclKind() != Decl::Export && - "should not perform lookups into transparent contexts"); + // For transparent DeclContext, we should lookup in their enclosing context. + if (getDeclKind() == Decl::LinkageSpec || getDeclKind() == Decl::Export) + return getParent()->lookup(Name); const DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 1780358cc348..0cf6e60b2a6c 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -79,10 +79,9 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasBasesWithFields(false), HasBasesWithNonStaticDataMembers(false), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), HasMutableFields(false), HasVariantMembers(false), - HasOnlyCMembers(true), HasInClassInitializer(false), + HasOnlyCMembers(true), HasInitMethod(false), HasInClassInitializer(false), HasUninitializedReferenceMember(false), HasUninitializedFields(false), - HasInheritedConstructor(false), - HasInheritedDefaultConstructor(false), + HasInheritedConstructor(false), HasInheritedDefaultConstructor(false), HasInheritedAssignment(false), NeedOverloadResolutionForCopyConstructor(false), NeedOverloadResolutionForMoveConstructor(false), @@ -3272,7 +3271,7 @@ void MSGuidDecl::anchor() {} MSGuidDecl::MSGuidDecl(DeclContext *DC, QualType T, Parts P) : ValueDecl(Decl::MSGuid, DC, SourceLocation(), DeclarationName(), T), - PartVal(P), APVal() {} + PartVal(P) {} MSGuidDecl *MSGuidDecl::Create(const ASTContext &C, QualType T, Parts P) { DeclContext *DC = C.getTranslationUnitDecl(); diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index ba827a79c022..f15dd78929e2 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -232,6 +232,18 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const { return &Ctx.Idents.get(ivarName.str()); } +ObjCPropertyDecl *ObjCContainerDecl::getProperty(const IdentifierInfo *Id, + bool IsInstance) const { + for (auto *LookupResult : lookup(Id)) { + if (auto *Prop = dyn_cast<ObjCPropertyDecl>(LookupResult)) { + if (Prop->isInstanceProperty() == IsInstance) { + return Prop; + } + } + } + return nullptr; +} + /// FindPropertyDeclaration - Finds declaration of the property given its name /// in 'PropertyId' and returns it. It returns 0, if not found. ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 044eb8f8f8e5..c3f1d1544f79 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -588,7 +588,7 @@ static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out, } EOut << " "; EOut.flush(); - Out << EOut.str(); + Out << Proto; } void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { @@ -731,7 +731,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { FT->getNoexceptExpr()->printPretty(EOut, nullptr, SubPolicy, Indentation, "\n", &Context); EOut.flush(); - Proto += EOut.str(); Proto += ")"; } } @@ -885,7 +884,10 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { } } - printDeclType(T, D->getName()); + printDeclType(T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters && + D->getIdentifier()) + ? D->getIdentifier()->deuglifiedName() + : D->getName()); Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { bool ImplicitInit = false; @@ -1131,8 +1133,12 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { else if (TTP->getDeclName()) Out << ' '; - if (TTP->getDeclName()) - Out << TTP->getDeclName(); + if (TTP->getDeclName()) { + if (Policy.CleanUglifiedParameters && TTP->getIdentifier()) + Out << TTP->getIdentifier()->deuglifiedName(); + else + Out << TTP->getDeclName(); + } } else if (auto *TD = D->getTemplatedDecl()) Visit(TD); else if (const auto *Concept = dyn_cast<ConceptDecl>(D)) { @@ -1742,8 +1748,12 @@ void DeclPrinter::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP) { else if (TTP->getDeclName()) Out << ' '; - if (TTP->getDeclName()) - Out << TTP->getDeclName(); + if (TTP->getDeclName()) { + if (Policy.CleanUglifiedParameters && TTP->getIdentifier()) + Out << TTP->getIdentifier()->deuglifiedName(); + else + Out << TTP->getDeclName(); + } if (TTP->hasDefaultArgument()) { Out << " = "; @@ -1755,7 +1765,8 @@ void DeclPrinter::VisitNonTypeTemplateParmDecl( const NonTypeTemplateParmDecl *NTTP) { StringRef Name; if (IdentifierInfo *II = NTTP->getIdentifier()) - Name = II->getName(); + Name = + Policy.CleanUglifiedParameters ? II->deuglifiedName() : II->getName(); printDeclType(NTTP->getType(), Name, NTTP->isParameterPack()); if (NTTP->hasDefaultArgument()) { diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 2530beb89d17..45e94847caee 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1281,7 +1281,7 @@ StringLiteral::getLocationOfByte(unsigned ByteNo, const SourceManager &SM, StringOffset = *StartTokenByteOffset; ByteNo -= StringOffset; } - while (1) { + while (true) { assert(TokNo < getNumConcatenated() && "Invalid byte number!"); SourceLocation StrTokLoc = getStrTokenLoc(TokNo); diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index 8cb8625e2a1a..c17453fb45fb 100644 --- a/clang/lib/AST/ExprConcepts.cpp +++ b/clang/lib/AST/ExprConcepts.cpp @@ -57,9 +57,9 @@ ConceptSpecializationExpr::ConceptSpecializationExpr( } ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, - unsigned NumTemplateArgs) - : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(), - NumTemplateArgs(NumTemplateArgs) { } + unsigned NumTemplateArgs) + : Expr(ConceptSpecializationExprClass, Empty), + NumTemplateArgs(NumTemplateArgs) {} void ConceptSpecializationExpr::setTemplateArguments( ArrayRef<TemplateArgument> Converted) { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 469339e8cd62..f9416e8e215d 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1706,8 +1706,8 @@ namespace { struct MemberPtr { MemberPtr() {} - explicit MemberPtr(const ValueDecl *Decl) : - DeclAndIsDerivedMember(Decl, false), Path() {} + explicit MemberPtr(const ValueDecl *Decl) + : DeclAndIsDerivedMember(Decl, false) {} /// The member or (direct or indirect) field referred to by this member /// pointer, or 0 if this is a null member pointer. @@ -4933,8 +4933,13 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, if (SS->getConditionVariable() && !EvaluateDecl(Info, SS->getConditionVariable())) return ESR_Failed; - if (!EvaluateInteger(SS->getCond(), Value, Info)) - return ESR_Failed; + if (SS->getCond()->isValueDependent()) { + if (!EvaluateDependentExpr(SS->getCond(), Info)) + return ESR_Failed; + } else { + if (!EvaluateInteger(SS->getCond(), Value, Info)) + return ESR_Failed; + } if (!CondScope.destroy()) return ESR_Failed; } @@ -6037,7 +6042,7 @@ static bool EvaluateArgs(ArrayRef<const Expr *> Args, CallRef Call, unsigned ASTIdx = Idx.getASTIndex(); if (ASTIdx >= Args.size()) continue; - ForbiddenNullArgs[ASTIdx] = 1; + ForbiddenNullArgs[ASTIdx] = true; } } } @@ -10434,6 +10439,15 @@ bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { if (!Evaluate(SubExprValue, Info, SubExpr)) return false; + // FIXME: This vector evaluator someday needs to be changed to be LValue + // aware/keep LValue information around, rather than dealing with just vector + // types directly. Until then, we cannot handle cases where the operand to + // these unary operators is an LValue. The only case I've been able to see + // cause this is operator++ assigning to a member expression (only valid in + // altivec compilations) in C mode, so this shouldn't limit us too much. + if (SubExprValue.isLValue()) + return false; + assert(SubExprValue.getVectorLength() == VD->getNumElements() && "Vector length doesn't match type?"); @@ -10680,28 +10694,55 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, bool HadZeroInit = Value->hasValue(); if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) { - unsigned N = CAT->getSize().getZExtValue(); + unsigned FinalSize = CAT->getSize().getZExtValue(); // Preserve the array filler if we had prior zero-initialization. APValue Filler = HadZeroInit && Value->hasArrayFiller() ? Value->getArrayFiller() : APValue(); - *Value = APValue(APValue::UninitArray(), N, N); - - if (HadZeroInit) - for (unsigned I = 0; I != N; ++I) - Value->getArrayInitializedElt(I) = Filler; + *Value = APValue(APValue::UninitArray(), 0, FinalSize); + if (FinalSize == 0) + return true; - // Initialize the elements. LValue ArrayElt = Subobject; ArrayElt.addArray(Info, E, CAT); - for (unsigned I = 0; I != N; ++I) - if (!VisitCXXConstructExpr(E, ArrayElt, &Value->getArrayInitializedElt(I), - CAT->getElementType()) || - !HandleLValueArrayAdjustment(Info, E, ArrayElt, CAT->getElementType(), - 1)) - return false; + // We do the whole initialization in two passes, first for just one element, + // then for the whole array. It's possible we may find out we can't do const + // init in the first pass, in which case we avoid allocating a potentially + // large array. We don't do more passes because expanding array requires + // copying the data, which is wasteful. + for (const unsigned N : {1u, FinalSize}) { + unsigned OldElts = Value->getArrayInitializedElts(); + if (OldElts == N) + break; + + // Expand the array to appropriate size. + APValue NewValue(APValue::UninitArray(), N, FinalSize); + for (unsigned I = 0; I < OldElts; ++I) + NewValue.getArrayInitializedElt(I).swap( + Value->getArrayInitializedElt(I)); + Value->swap(NewValue); + + if (HadZeroInit) + for (unsigned I = OldElts; I < N; ++I) + Value->getArrayInitializedElt(I) = Filler; + + // Initialize the elements. + for (unsigned I = OldElts; I < N; ++I) { + if (!VisitCXXConstructExpr(E, ArrayElt, + &Value->getArrayInitializedElt(I), + CAT->getElementType()) || + !HandleLValueArrayAdjustment(Info, E, ArrayElt, + CAT->getElementType(), 1)) + return false; + // When checking for const initilization any diagnostic is considered + // an error. + if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() && + !Info.keepEvaluatingAfterFailure()) + return false; + } + } return true; } diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index 83b952116a5e..102bcca96a38 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -21,7 +21,6 @@ using clang::analyze_format_string::FormatStringHandler; using clang::analyze_format_string::FormatSpecifier; using clang::analyze_format_string::LengthModifier; using clang::analyze_format_string::OptionalAmount; -using clang::analyze_format_string::PositionContext; using clang::analyze_format_string::ConversionSpecifier; using namespace clang; diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 5c8cb4274260..da538aa332ff 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -207,13 +207,13 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) { - OptionScope<Emitter> Scope(this, /*discardResult=*/true); + OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true); return this->Visit(E); } template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) { - OptionScope<Emitter> Scope(this, /*discardResult=*/false); + OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false); return this->Visit(E); } diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index 716f28551e58..124a6ff03f18 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -28,8 +28,6 @@ namespace clang { class QualType; namespace interp { -class Function; -class State; template <class Emitter> class LocalScope; template <class Emitter> class RecordScope; diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h index d9c0b64ed4b8..3bc665b84b4d 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.h +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h @@ -25,11 +25,7 @@ #include "llvm/ADT/Optional.h" namespace clang { -class QualType; - namespace interp { -class Function; -class State; template <class Emitter> class LoopScope; template <class Emitter> class SwitchScope; diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index 4f25ff977b81..0627d9fb14f5 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -23,7 +23,6 @@ namespace clang { class ASTContext; class LangOptions; -class Stmt; class FunctionDecl; class VarDecl; diff --git a/clang/lib/AST/Interp/InterpBlock.h b/clang/lib/AST/Interp/InterpBlock.h index 0ccdef221c83..2d5386e60b8c 100644 --- a/clang/lib/AST/Interp/InterpBlock.h +++ b/clang/lib/AST/Interp/InterpBlock.h @@ -25,10 +25,8 @@ namespace clang { namespace interp { class Block; class DeadBlock; -class Context; class InterpState; class Pointer; -class Function; enum PrimType : unsigned; /// A memory block, either on the stack or in the heap. diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index f2f6e0e76018..587531aec82a 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -26,10 +26,7 @@ namespace clang { namespace interp { class Block; class DeadBlock; -class Context; -class InterpState; class Pointer; -class Function; enum PrimType : unsigned; /// A pointer to a memory block, live or dead. diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h index f5f4f8e5c32d..de4bf9bf802e 100644 --- a/clang/lib/AST/Interp/PrimType.h +++ b/clang/lib/AST/Interp/PrimType.h @@ -81,35 +81,27 @@ inline bool isPrimitiveIntegral(PrimType Type) { /// Helper macro to simplify type switches. /// The macro implicitly exposes a type T in the scope of the inner block. #define TYPE_SWITCH_CASE(Name, B) \ - case Name: { using T = PrimConv<Name>::T; do {B;} while(0); break; } + case Name: { using T = PrimConv<Name>::T; B; break; } #define TYPE_SWITCH(Expr, B) \ - switch (Expr) { \ - TYPE_SWITCH_CASE(PT_Sint8, B) \ - TYPE_SWITCH_CASE(PT_Uint8, B) \ - TYPE_SWITCH_CASE(PT_Sint16, B) \ - TYPE_SWITCH_CASE(PT_Uint16, B) \ - TYPE_SWITCH_CASE(PT_Sint32, B) \ - TYPE_SWITCH_CASE(PT_Uint32, B) \ - TYPE_SWITCH_CASE(PT_Sint64, B) \ - TYPE_SWITCH_CASE(PT_Uint64, B) \ - TYPE_SWITCH_CASE(PT_Bool, B) \ - TYPE_SWITCH_CASE(PT_Ptr, B) \ - } + do { \ + switch (Expr) { \ + TYPE_SWITCH_CASE(PT_Sint8, B) \ + TYPE_SWITCH_CASE(PT_Uint8, B) \ + TYPE_SWITCH_CASE(PT_Sint16, B) \ + TYPE_SWITCH_CASE(PT_Uint16, B) \ + TYPE_SWITCH_CASE(PT_Sint32, B) \ + TYPE_SWITCH_CASE(PT_Uint32, B) \ + TYPE_SWITCH_CASE(PT_Sint64, B) \ + TYPE_SWITCH_CASE(PT_Uint64, B) \ + TYPE_SWITCH_CASE(PT_Bool, B) \ + TYPE_SWITCH_CASE(PT_Ptr, B) \ + } \ + } while (0) #define COMPOSITE_TYPE_SWITCH(Expr, B, D) \ - switch (Expr) { \ - TYPE_SWITCH_CASE(PT_Ptr, B) \ - default: do { D; } while(0); break; \ - } -#define INT_TYPE_SWITCH(Expr, B) \ - switch (Expr) { \ - TYPE_SWITCH_CASE(PT_Sint8, B) \ - TYPE_SWITCH_CASE(PT_Uint8, B) \ - TYPE_SWITCH_CASE(PT_Sint16, B) \ - TYPE_SWITCH_CASE(PT_Uint16, B) \ - TYPE_SWITCH_CASE(PT_Sint32, B) \ - TYPE_SWITCH_CASE(PT_Uint32, B) \ - TYPE_SWITCH_CASE(PT_Sint64, B) \ - TYPE_SWITCH_CASE(PT_Uint64, B) \ - default: llvm_unreachable("not an integer"); \ - } + do { \ + switch (Expr) { \ + TYPE_SWITCH_CASE(PT_Ptr, B) \ + default: { D; break; } \ + } \ + } while (0) #endif diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h index c81ec777a5fe..ca985af8ad30 100644 --- a/clang/lib/AST/Interp/Program.h +++ b/clang/lib/AST/Interp/Program.h @@ -29,15 +29,12 @@ namespace clang { class RecordDecl; class Expr; class FunctionDecl; -class Stmt; class StringLiteral; class VarDecl; namespace interp { class Context; -class State; class Record; -class Scope; /// The program contains and links the bytecode for all functions. class Program { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 7afc1250a36f..2e734e2b28cd 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -659,8 +659,7 @@ bool ItaniumMangleContextImpl::isUniqueInternalLinkageDecl( } bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { - const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (FD) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { LanguageLinkage L = FD->getLanguageLinkage(); // Overloadable functions need mangling. if (FD->hasAttr<OverloadableAttr>()) @@ -696,21 +695,24 @@ bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { if (!getASTContext().getLangOpts().CPlusPlus) return false; - const VarDecl *VD = dyn_cast<VarDecl>(D); - if (VD && !isa<DecompositionDecl>(D)) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { + // Decompositions are mangled. + if (isa<DecompositionDecl>(VD)) + return true; + // C variables are not mangled. if (VD->isExternC()) return false; - // Variables at global scope with non-internal linkage are not mangled + // Variables at global scope with non-internal linkage are not mangled. const DeclContext *DC = getEffectiveDeclContext(D); // Check for extern variable declared locally. if (DC->isFunctionOrMethod() && D->hasLinkage()) - while (!DC->isNamespace() && !DC->isTranslationUnit()) + while (!DC->isFileContext()) DC = getEffectiveParentContext(DC); if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage && !CXXNameMangler::shouldHaveAbiTags(*this, VD) && - !isa<VarTemplateSpecializationDecl>(D)) + !isa<VarTemplateSpecializationDecl>(VD)) return false; } @@ -5889,9 +5891,11 @@ void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) { } void CXXNameMangler::mangleSeqID(unsigned SeqID) { - if (SeqID == 1) + if (SeqID == 0) { + // Nothing. + } else if (SeqID == 1) { Out << '0'; - else if (SeqID > 1) { + } else { SeqID--; // <seq-id> is encoded in base-36, using digits and upper case letters. diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 54dbf484f377..984da9909ce2 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -225,11 +225,17 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) { if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) if (!MD->isStatic()) ++ArgWords; - for (const auto &AT : Proto->param_types()) + for (const auto &AT : Proto->param_types()) { + // If an argument type is incomplete there is no way to get its size to + // correctly encode into the mangling scheme. + // Follow GCCs behaviour by simply breaking out of the loop. + if (AT->isIncompleteType()) + break; // Size should be aligned to pointer size. ArgWords += llvm::alignTo(ASTContext.getTypeSize(AT), TI.getPointerWidth(0)) / TI.getPointerWidth(0); + } Out << ((TI.getPointerWidth(0) / 8) * ArgWords); } diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp index 53d7e0b042ff..b7dc0e62e66a 100644 --- a/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/clang/lib/AST/MicrosoftCXXABI.cpp @@ -36,8 +36,8 @@ class MicrosoftNumberingContext : public MangleNumberingContext { public: MicrosoftNumberingContext() - : MangleNumberingContext(), LambdaManglingNumber(0), - StaticLocalNumber(0), StaticThreadlocalNumber(0) {} + : LambdaManglingNumber(0), StaticLocalNumber(0), + StaticThreadlocalNumber(0) {} unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { return ++LambdaManglingNumber; diff --git a/clang/lib/AST/OSLog.cpp b/clang/lib/AST/OSLog.cpp index 094c0102854b..4cc5def0651f 100644 --- a/clang/lib/AST/OSLog.cpp +++ b/clang/lib/AST/OSLog.cpp @@ -56,8 +56,8 @@ public: } bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, - const char *StartSpecifier, - unsigned SpecifierLen) override { + const char *StartSpecifier, unsigned SpecifierLen, + const TargetInfo &) override { if (!FS.consumesDataArgument() && FS.getConversionSpecifier().getKind() != clang::analyze_format_string::ConversionSpecifier::PrintErrno) diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index e2569c9e20df..c6c41abc7e9a 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -428,7 +428,7 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, continue; // We have a format specifier. Pass it to the callback. if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), - I - FSR.getStart())) + I - FSR.getStart(), Target)) return true; } assert(I == E && "Format string not exhausted"); @@ -711,8 +711,8 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, CS.setKind(ConversionSpecifier::sArg); // Disable irrelevant flags - HasAlternativeForm = 0; - HasLeadingZeroes = 0; + HasAlternativeForm = false; + HasLeadingZeroes = false; // Set the long length modifier for wide characters if (QT->getPointeeType()->isWideCharType()) @@ -878,9 +878,9 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, CS.setKind(ConversionSpecifier::cArg); LM.setKind(LengthModifier::None); Precision.setHowSpecified(OptionalAmount::NotSpecified); - HasAlternativeForm = 0; - HasLeadingZeroes = 0; - HasPlusPrefix = 0; + HasAlternativeForm = false; + HasLeadingZeroes = false; + HasPlusPrefix = false; } // Test for Floating type first as LongDouble can pass isUnsignedIntegerType else if (QT->isRealFloatingType()) { @@ -888,12 +888,12 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, } else if (QT->isSignedIntegerType()) { CS.setKind(ConversionSpecifier::dArg); - HasAlternativeForm = 0; + HasAlternativeForm = false; } else if (QT->isUnsignedIntegerType()) { CS.setKind(ConversionSpecifier::uArg); - HasAlternativeForm = 0; - HasPlusPrefix = 0; + HasAlternativeForm = false; + HasPlusPrefix = false; } else { llvm_unreachable("Unexpected type"); } diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 3e39ec1c718d..61a30ead165e 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2021,6 +2021,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, CharUnits UnpackedFieldAlign = !DefaultsToAIXPowerAlignment ? FieldAlign : PreferredAlign; CharUnits UnpackedFieldOffset = FieldOffset; + CharUnits OriginalFieldAlign = UnpackedFieldAlign; if (FieldPacked) { FieldAlign = CharUnits::One(); @@ -2105,6 +2106,22 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, // Remember max struct/class ABI-specified alignment. UnadjustedAlignment = std::max(UnadjustedAlignment, FieldAlign); UpdateAlignment(FieldAlign, UnpackedFieldAlign, PreferredAlign); + + // For checking the alignment of inner fields against + // the alignment of its parent record. + if (const RecordDecl *RD = D->getParent()) { + // Check if packed attribute or pragma pack is present. + if (RD->hasAttr<PackedAttr>() || !MaxFieldAlignment.isZero()) + if (FieldAlign < OriginalFieldAlign) + if (D->getType()->isRecordType()) { + // If the offset is a multiple of the alignment of + // the type, raise the warning. + // TODO: Takes no account the alignment of the outer struct + if (FieldOffset % OriginalFieldAlign != 0) + Diag(D->getLocation(), diag::warn_unaligned_access) + << Context.getTypeDeclType(RD) << D->getName() << D->getType(); + } + } } void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 4f76f6ec12ed..be19d3b2cce2 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -568,21 +568,20 @@ void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C, /// translate this into a numeric value needed to reference the same operand. /// This returns -1 if the operand name is invalid. int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const { - unsigned NumPlusOperands = 0; - // Check if this is an output operand. - for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) { + unsigned NumOutputs = getNumOutputs(); + for (unsigned i = 0; i != NumOutputs; ++i) if (getOutputName(i) == SymbolicName) return i; - } - for (unsigned i = 0, e = getNumInputs(); i != e; ++i) + unsigned NumInputs = getNumInputs(); + for (unsigned i = 0; i != NumInputs; ++i) if (getInputName(i) == SymbolicName) - return getNumOutputs() + NumPlusOperands + i; + return NumOutputs + i; for (unsigned i = 0, e = getNumLabels(); i != e; ++i) if (getLabelName(i) == SymbolicName) - return i + getNumOutputs() + getNumInputs(); + return NumOutputs + NumInputs + getNumPlusOperands() + i; // Not found. return -1; diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index b336a0637d5e..8a9f73d3dbf0 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -518,7 +518,7 @@ OMPSectionDirective *OMPSectionDirective::Create(const ASTContext &C, bool HasCancel) { auto *Dir = createDirective<OMPSectionDirective>(C, llvm::None, AssociatedStmt, - /*NumChildre=*/0, StartLoc, EndLoc); + /*NumChildren=*/0, StartLoc, EndLoc); Dir->setHasCancel(HasCancel); return Dir; } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index b65a38d1e566..adc0720fe000 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1030,7 +1030,12 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { Qualifier->print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; - OS << Node->getNameInfo(); + if (Policy.CleanUglifiedParameters && + isa<ParmVarDecl, NonTypeTemplateParmDecl>(Node->getDecl()) && + Node->getDecl()->getIdentifier()) + OS << Node->getDecl()->getIdentifier()->deuglifiedName(); + else + Node->getNameInfo().printName(OS, Policy); if (Node->hasExplicitTemplateArgs()) { const TemplateParameterList *TPL = nullptr; if (!Node->hadMultipleCandidates()) @@ -2069,7 +2074,10 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { } else { NeedComma = true; } - std::string ParamStr = P->getNameAsString(); + std::string ParamStr = + (Policy.CleanUglifiedParameters && P->getIdentifier()) + ? P->getIdentifier()->deuglifiedName().str() + : P->getNameAsString(); P->getOriginalType().print(OS, Policy, ParamStr); } if (Method->isVariadic()) { diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index c8bd74f0b5bb..05d7d58b71c4 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -223,8 +223,12 @@ bool TemplateName::containsUnexpandedParameterPack() const { void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, Qualified Qual) const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) - if (Qual == Qualified::Fully && - getDependence() != TemplateNameDependenceScope::DependentInstantiation) + if (Policy.CleanUglifiedParameters && + isa<TemplateTemplateParmDecl>(Template) && Template->getIdentifier()) + OS << Template->getIdentifier()->deuglifiedName(); + else if (Qual == Qualified::Fully && + getDependence() != + TemplateNameDependenceScope::DependentInstantiation) Template->printQualifiedName(OS, Policy); else OS << *Template; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index c771fe264b0c..774b3e94159d 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -194,7 +194,7 @@ void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID, ID.AddInteger(ArraySize.getZExtValue()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); - ID.AddBoolean(SizeExpr != 0); + ID.AddBoolean(SizeExpr != nullptr); if (SizeExpr) SizeExpr->Profile(ID, Context, true); } diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index c3ed08d5a8b3..13aa54c48f66 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -622,6 +622,7 @@ void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setFoundDecl(nullptr); setRAngleLoc(Loc); setLAngleLoc(Loc); + setRParenLoc(Loc); TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), getArgInfos(), Loc); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 2a33a69f288d..bba323f651aa 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -280,7 +280,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::Attributed: { // We still want to print the address_space before the type if it is an // address_space attribute. - const auto *AttrTy = cast<AttributedType>(T); + const auto *AttrTy = cast<AttributedType>(UnderlyingType); CanPrefixQualifiers = AttrTy->getAttrKind() == attr::AddressSpace; } } @@ -1418,7 +1418,8 @@ void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T, } OS << "auto"; } else if (IdentifierInfo *Id = T->getIdentifier()) - OS << Id->getName(); + OS << (Policy.CleanUglifiedParameters ? Id->deuglifiedName() + : Id->getName()); else OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index f938565c3cb4..24586d6b70d4 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -2328,7 +2328,7 @@ ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) { return; ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(), - /*MostDerivedClassIsVirtual=*/0, RD); + /*MostDerivedClassIsVirtual=*/false, RD); Entry = CreateVTableLayout(Builder); MethodVTableIndices.insert(Builder.vtable_indices_begin(), diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h index fa9d42247e24..3e9c4f31b84d 100644 --- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -524,8 +524,9 @@ variadicMatcherDescriptor(StringRef MatcherName, SourceRange NameRange, } return {}; } - InnerArgs.set_size(i + 1); - InnerArgsPtr[i] = new (&InnerArgs[i]) ArgT(ArgTraits::get(Value)); + assert(InnerArgs.size() < InnerArgs.capacity()); + InnerArgs.emplace_back(ArgTraits::get(Value)); + InnerArgsPtr[i] = &InnerArgs[i]; } return outvalueToVariantMatcher(Func(InnerArgsPtr)); } @@ -1166,4 +1167,4 @@ std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall( } // namespace ast_matchers } // namespace clang -#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H +#endif // LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 4f3efdb0a663..47db6b51966a 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -404,7 +404,9 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isComparisonOperator); REGISTER_MATCHER(isConst); REGISTER_MATCHER(isConstQualified); + REGISTER_MATCHER(isConsteval); REGISTER_MATCHER(isConstexpr); + REGISTER_MATCHER(isConstinit); REGISTER_MATCHER(isCopyAssignmentOperator); REGISTER_MATCHER(isCopyConstructor); REGISTER_MATCHER(isDefaultConstructor); diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 9ef3b5b6277a..8246854dc1b5 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -531,9 +531,7 @@ class CFGBuilder { public: explicit CFGBuilder(ASTContext *astContext, const CFG::BuildOptions &buildOpts) - : Context(astContext), cfg(new CFG()), // crew a new CFG - ConstructionContextMap(), BuildOpts(buildOpts) {} - + : Context(astContext), cfg(new CFG()), BuildOpts(buildOpts) {} // buildCFG - Used by external clients to construct the CFG. std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *Statement); @@ -3354,7 +3352,7 @@ CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) { // Save "Succ" in BackpatchBlocks. In the backpatch processing, "Succ" is // used to avoid adding "Succ" again. BackpatchBlocks.push_back(JumpSource(Succ, ScopePos)); - return Block; + return VisitChildren(G); } CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp new file mode 100644 index 000000000000..3ad2ed640cc1 --- /dev/null +++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -0,0 +1,69 @@ +//===- ControlFlowContext.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a ControlFlowContext class that is used by dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Error.h" +#include <utility> + +namespace clang { +namespace dataflow { + +/// Returns a map from statements to basic blocks that contain them. +static llvm::DenseMap<const Stmt *, const CFGBlock *> +buildStmtToBasicBlockMap(const CFG &Cfg) { + llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock; + for (const CFGBlock *Block : Cfg) { + if (Block == nullptr) + continue; + + for (const CFGElement &Element : *Block) { + auto Stmt = Element.getAs<CFGStmt>(); + if (!Stmt.hasValue()) + continue; + + StmtToBlock[Stmt.getValue().getStmt()] = Block; + } + } + return StmtToBlock; +} + +llvm::Expected<ControlFlowContext> +ControlFlowContext::build(const Decl *D, Stmt *S, ASTContext *C) { + CFG::BuildOptions Options; + Options.PruneTriviallyFalseEdges = false; + Options.AddImplicitDtors = true; + Options.AddTemporaryDtors = true; + Options.AddInitializers = true; + Options.AddCXXDefaultInitExprInCtors = true; + + // Ensure that all sub-expressions in basic blocks are evaluated. + Options.setAllAlwaysAdd(); + + auto Cfg = CFG::buildCFG(D, S, C, Options); + if (Cfg == nullptr) + return llvm::createStringError( + std::make_error_code(std::errc::invalid_argument), + "CFG::buildCFG failed"); + + llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock = + buildStmtToBasicBlockMap(*Cfg); + return ControlFlowContext(std::move(Cfg), std::move(StmtToBlock)); +} + +} // namespace dataflow +} // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp new file mode 100644 index 000000000000..938f7338b640 --- /dev/null +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -0,0 +1,318 @@ +//===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines an Environment class that is used by dataflow analyses +// that run over Control-Flow Graphs (CFGs) to keep track of the state of the +// program at given program points. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/DataflowLattice.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "clang/Analysis/FlowSensitive/Value.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/ErrorHandling.h" +#include <memory> +#include <utility> + +namespace clang { +namespace dataflow { + +/// Returns a map consisting of key-value entries that are present in both maps. +template <typename K, typename V> +llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1, + const llvm::DenseMap<K, V> &Map2) { + llvm::DenseMap<K, V> Result; + for (auto &Entry : Map1) { + auto It = Map2.find(Entry.first); + if (It != Map2.end() && Entry.second == It->second) + Result.insert({Entry.first, Entry.second}); + } + return Result; +} + +Environment::Environment(DataflowAnalysisContext &DACtx, + const DeclContext &DeclCtx) + : Environment(DACtx) { + if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) { + for (const auto *ParamDecl : FuncDecl->parameters()) { + assert(ParamDecl != nullptr); + auto &ParamLoc = createStorageLocation(*ParamDecl); + setStorageLocation(*ParamDecl, ParamLoc); + if (Value *ParamVal = createValue(ParamDecl->getType())) + setValue(ParamLoc, *ParamVal); + } + } + + if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) { + if (!MethodDecl->isStatic()) { + QualType ThisPointeeType = MethodDecl->getThisObjectType(); + // FIXME: Add support for union types. + if (!ThisPointeeType->isUnionType()) { + auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType); + DACtx.setThisPointeeStorageLocation(ThisPointeeLoc); + if (Value *ThisPointeeVal = createValue(ThisPointeeType)) + setValue(ThisPointeeLoc, *ThisPointeeVal); + } + } + } +} + +bool Environment::operator==(const Environment &Other) const { + assert(DACtx == Other.DACtx); + return DeclToLoc == Other.DeclToLoc && LocToVal == Other.LocToVal; +} + +LatticeJoinEffect Environment::join(const Environment &Other, + Environment::Merger &Merger) { + assert(DACtx == Other.DACtx); + + auto Effect = LatticeJoinEffect::Unchanged; + + const unsigned DeclToLocSizeBefore = DeclToLoc.size(); + DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc); + if (DeclToLocSizeBefore != DeclToLoc.size()) + Effect = LatticeJoinEffect::Changed; + + const unsigned ExprToLocSizeBefore = ExprToLoc.size(); + ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc); + if (ExprToLocSizeBefore != ExprToLoc.size()) + Effect = LatticeJoinEffect::Changed; + + llvm::DenseMap<const StorageLocation *, Value *> MergedLocToVal; + for (auto &Entry : LocToVal) { + const StorageLocation *Loc = Entry.first; + assert(Loc != nullptr); + + Value *Val = Entry.second; + assert(Val != nullptr); + + auto It = Other.LocToVal.find(Loc); + if (It == Other.LocToVal.end()) + continue; + assert(It->second != nullptr); + + if (It->second == Val) { + MergedLocToVal.insert({Loc, Val}); + continue; + } + + // FIXME: Consider destroying `MergedValue` immediately if `Merger::merge` + // returns false to avoid storing unneeded values in `DACtx`. + if (Value *MergedVal = createValue(Loc->getType())) + if (Merger.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this)) + MergedLocToVal.insert({Loc, MergedVal}); + } + const unsigned LocToValSizeBefore = LocToVal.size(); + LocToVal = std::move(MergedLocToVal); + if (LocToValSizeBefore != LocToVal.size()) + Effect = LatticeJoinEffect::Changed; + + return Effect; +} + +StorageLocation &Environment::createStorageLocation(QualType Type) { + assert(!Type.isNull()); + if (Type->isStructureOrClassType() || Type->isUnionType()) { + // FIXME: Explore options to avoid eager initialization of fields as some of + // them might not be needed for a particular analysis. + llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; + for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { + FieldLocs.insert({Field, &createStorageLocation(Field->getType())}); + } + return takeOwnership( + std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs))); + } + return takeOwnership(std::make_unique<ScalarStorageLocation>(Type)); +} + +StorageLocation &Environment::createStorageLocation(const VarDecl &D) { + // Evaluated declarations are always assigned the same storage locations to + // ensure that the environment stabilizes across loop iterations. Storage + // locations for evaluated declarations are stored in the analysis context. + if (auto *Loc = DACtx->getStorageLocation(D)) + return *Loc; + auto &Loc = createStorageLocation(D.getType()); + DACtx->setStorageLocation(D, Loc); + return Loc; +} + +StorageLocation &Environment::createStorageLocation(const Expr &E) { + // Evaluated expressions are always assigned the same storage locations to + // ensure that the environment stabilizes across loop iterations. Storage + // locations for evaluated expressions are stored in the analysis context. + if (auto *Loc = DACtx->getStorageLocation(E)) + return *Loc; + auto &Loc = createStorageLocation(E.getType()); + DACtx->setStorageLocation(E, Loc); + return Loc; +} + +void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { + assert(DeclToLoc.find(&D) == DeclToLoc.end()); + DeclToLoc[&D] = &Loc; +} + +StorageLocation *Environment::getStorageLocation(const ValueDecl &D, + SkipPast SP) const { + auto It = DeclToLoc.find(&D); + return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP); +} + +void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { + assert(ExprToLoc.find(&E) == ExprToLoc.end()); + ExprToLoc[&E] = &Loc; +} + +StorageLocation *Environment::getStorageLocation(const Expr &E, + SkipPast SP) const { + auto It = ExprToLoc.find(&E); + return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP); +} + +StorageLocation *Environment::getThisPointeeStorageLocation() const { + return DACtx->getThisPointeeStorageLocation(); +} + +void Environment::setValue(const StorageLocation &Loc, Value &Val) { + LocToVal[&Loc] = &Val; + + if (auto *StructVal = dyn_cast<StructValue>(&Val)) { + auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc); + + const QualType Type = AggregateLoc.getType(); + assert(Type->isStructureOrClassType()); + + for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { + assert(Field != nullptr); + setValue(AggregateLoc.getChild(*Field), StructVal->getChild(*Field)); + } + } +} + +Value *Environment::getValue(const StorageLocation &Loc) const { + auto It = LocToVal.find(&Loc); + return It == LocToVal.end() ? nullptr : It->second; +} + +Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const { + auto *Loc = getStorageLocation(D, SP); + if (Loc == nullptr) + return nullptr; + return getValue(*Loc); +} + +Value *Environment::getValue(const Expr &E, SkipPast SP) const { + auto *Loc = getStorageLocation(E, SP); + if (Loc == nullptr) + return nullptr; + return getValue(*Loc); +} + +Value *Environment::createValue(QualType Type) { + llvm::DenseSet<QualType> Visited; + return createValueUnlessSelfReferential(Type, Visited); +} + +Value *Environment::createValueUnlessSelfReferential( + QualType Type, llvm::DenseSet<QualType> &Visited) { + assert(!Type.isNull()); + + if (Type->isIntegerType()) { + return &takeOwnership(std::make_unique<IntegerValue>()); + } + + if (Type->isReferenceType()) { + QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType(); + auto &PointeeLoc = createStorageLocation(PointeeType); + + if (!Visited.contains(PointeeType.getCanonicalType())) { + Visited.insert(PointeeType.getCanonicalType()); + Value *PointeeVal = + createValueUnlessSelfReferential(PointeeType, Visited); + Visited.erase(PointeeType.getCanonicalType()); + + if (PointeeVal != nullptr) + setValue(PointeeLoc, *PointeeVal); + } + + return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc)); + } + + if (Type->isPointerType()) { + QualType PointeeType = Type->getAs<PointerType>()->getPointeeType(); + auto &PointeeLoc = createStorageLocation(PointeeType); + + if (!Visited.contains(PointeeType.getCanonicalType())) { + Visited.insert(PointeeType.getCanonicalType()); + Value *PointeeVal = + createValueUnlessSelfReferential(PointeeType, Visited); + Visited.erase(PointeeType.getCanonicalType()); + + if (PointeeVal != nullptr) + setValue(PointeeLoc, *PointeeVal); + } + + return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc)); + } + + if (Type->isStructureOrClassType()) { + // FIXME: Initialize only fields that are accessed in the context that is + // being analyzed. + llvm::DenseMap<const ValueDecl *, Value *> FieldValues; + for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { + assert(Field != nullptr); + + QualType FieldType = Field->getType(); + if (Visited.contains(FieldType.getCanonicalType())) + continue; + + Visited.insert(FieldType.getCanonicalType()); + FieldValues.insert( + {Field, createValueUnlessSelfReferential(FieldType, Visited)}); + Visited.erase(FieldType.getCanonicalType()); + } + + return &takeOwnership( + std::make_unique<StructValue>(std::move(FieldValues))); + } + + return nullptr; +} + +StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const { + switch (SP) { + case SkipPast::None: + return Loc; + case SkipPast::Reference: + // References cannot be chained so we only need to skip past one level of + // indirection. + if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc))) + return Val->getPointeeLoc(); + return Loc; + case SkipPast::ReferenceThenPointer: + StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference); + if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef))) + return Val->getPointeeLoc(); + return LocPastRef; + } + llvm_unreachable("bad SkipPast kind"); +} + +const StorageLocation &Environment::skip(const StorageLocation &Loc, + SkipPast SP) const { + return skip(*const_cast<StorageLocation *>(&Loc), SP); +} + +} // namespace dataflow +} // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp new file mode 100644 index 000000000000..51a86b727e33 --- /dev/null +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -0,0 +1,462 @@ +//===-- Transfer.cpp --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines transfer functions that evaluate program statements and +// update an environment accordingly. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/FlowSensitive/Transfer.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Basic/OperatorKinds.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <memory> +#include <tuple> + +namespace clang { +namespace dataflow { + +static const Expr *skipExprWithCleanups(const Expr *E) { + if (auto *C = dyn_cast_or_null<ExprWithCleanups>(E)) + return C->getSubExpr(); + return E; +} + +class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { +public: + TransferVisitor(Environment &Env) : Env(Env) {} + + void VisitBinaryOperator(const BinaryOperator *S) { + if (S->getOpcode() == BO_Assign) { + // The CFG does not contain `ParenExpr` as top-level statements in basic + // blocks, however sub-expressions can still be of that type. + assert(S->getLHS() != nullptr); + const Expr *LHS = S->getLHS()->IgnoreParens(); + + assert(LHS != nullptr); + auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference); + if (LHSLoc == nullptr) + return; + + // The CFG does not contain `ParenExpr` as top-level statements in basic + // blocks, however sub-expressions can still be of that type. + assert(S->getRHS() != nullptr); + const Expr *RHS = S->getRHS()->IgnoreParens(); + + assert(RHS != nullptr); + Value *RHSVal = Env.getValue(*RHS, SkipPast::Reference); + if (RHSVal == nullptr) + return; + + // Assign a value to the storage location of the left-hand side. + Env.setValue(*LHSLoc, *RHSVal); + + // Assign a storage location for the whole expression. + Env.setStorageLocation(*S, *LHSLoc); + } + // FIXME: Add support for BO_EQ, BO_NE. + } + + void VisitDeclRefExpr(const DeclRefExpr *S) { + assert(S->getDecl() != nullptr); + auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None); + if (DeclLoc == nullptr) + return; + + if (S->getDecl()->getType()->isReferenceType()) { + Env.setStorageLocation(*S, *DeclLoc); + } else { + auto &Loc = Env.createStorageLocation(*S); + auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc)); + Env.setStorageLocation(*S, Loc); + Env.setValue(Loc, Val); + } + } + + void VisitDeclStmt(const DeclStmt *S) { + // Group decls are converted into single decls in the CFG so the cast below + // is safe. + const auto &D = *cast<VarDecl>(S->getSingleDecl()); + auto &Loc = Env.createStorageLocation(D); + Env.setStorageLocation(D, Loc); + + const Expr *InitExpr = D.getInit(); + if (InitExpr == nullptr) { + // No initializer expression - associate `Loc` with a new value. + if (Value *Val = Env.createValue(D.getType())) + Env.setValue(Loc, *Val); + return; + } + + // The CFG does not contain `ParenExpr` as top-level statements in basic + // blocks, however sub-expressions can still be of that type. + InitExpr = skipExprWithCleanups(D.getInit()->IgnoreParens()); + assert(InitExpr != nullptr); + + if (D.getType()->isReferenceType()) { + // Initializing a reference variable - do not create a reference to + // reference. + if (auto *InitExprLoc = + Env.getStorageLocation(*InitExpr, SkipPast::Reference)) { + auto &Val = + Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc)); + Env.setValue(Loc, Val); + } else { + // FIXME: The initializer expression must always be assigned a value. + // Replace this with an assert when we have sufficient coverage of + // language features. + if (Value *Val = Env.createValue(D.getType())) + Env.setValue(Loc, *Val); + } + return; + } + + if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) { + Env.setValue(Loc, *InitExprVal); + } else if (!D.getType()->isStructureOrClassType()) { + // FIXME: The initializer expression must always be assigned a value. + // Replace this with an assert when we have sufficient coverage of + // language features. + if (Value *Val = Env.createValue(D.getType())) + Env.setValue(Loc, *Val); + } else { + llvm_unreachable("structs and classes must always be assigned values"); + } + } + + void VisitImplicitCastExpr(const ImplicitCastExpr *S) { + // The CFG does not contain `ParenExpr` as top-level statements in basic + // blocks, however sub-expressions can still be of that type. + assert(S->getSubExpr() != nullptr); + const Expr *SubExpr = S->getSubExpr()->IgnoreParens(); + assert(SubExpr != nullptr); + + switch (S->getCastKind()) { + case CK_LValueToRValue: { + auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference); + if (SubExprVal == nullptr) + break; + + auto &ExprLoc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, ExprLoc); + Env.setValue(ExprLoc, *SubExprVal); + break; + } + case CK_NoOp: { + // FIXME: Consider making `Environment::getStorageLocation` skip noop + // expressions (this and other similar expressions in the file) instead of + // assigning them storage locations. + auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); + if (SubExprLoc == nullptr) + break; + + Env.setStorageLocation(*S, *SubExprLoc); + break; + } + default: + // FIXME: Add support for CK_UserDefinedConversion, + // CK_ConstructorConversion, CK_UncheckedDerivedToBase. + break; + } + } + + void VisitUnaryOperator(const UnaryOperator *S) { + // The CFG does not contain `ParenExpr` as top-level statements in basic + // blocks, however sub-expressions can still be of that type. + assert(S->getSubExpr() != nullptr); + const Expr *SubExpr = S->getSubExpr()->IgnoreParens(); + assert(SubExpr != nullptr); + + switch (S->getOpcode()) { + case UO_Deref: { + // Skip past a reference to handle dereference of a dependent pointer. + const auto *SubExprVal = cast_or_null<PointerValue>( + Env.getValue(*SubExpr, SkipPast::Reference)); + if (SubExprVal == nullptr) + break; + + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>( + SubExprVal->getPointeeLoc()))); + break; + } + case UO_AddrOf: { + // Do not form a pointer to a reference. If `SubExpr` is assigned a + // `ReferenceValue` then form a value that points to the location of its + // pointee. + StorageLocation *PointeeLoc = + Env.getStorageLocation(*SubExpr, SkipPast::Reference); + if (PointeeLoc == nullptr) + break; + + auto &PointerLoc = Env.createStorageLocation(*S); + auto &PointerVal = + Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc)); + Env.setStorageLocation(*S, PointerLoc); + Env.setValue(PointerLoc, PointerVal); + break; + } + default: + // FIXME: Add support for UO_LNot. + break; + } + } + + void VisitCXXThisExpr(const CXXThisExpr *S) { + auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); + assert(ThisPointeeLoc != nullptr); + + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + Env.setValue(Loc, Env.takeOwnership( + std::make_unique<PointerValue>(*ThisPointeeLoc))); + } + + void VisitMemberExpr(const MemberExpr *S) { + ValueDecl *Member = S->getMemberDecl(); + assert(Member != nullptr); + + // FIXME: Consider assigning pointer values to function member expressions. + if (Member->isFunctionOrFunctionTemplate()) + return; + + // The receiver can be either a value or a pointer to a value. Skip past the + // indirection to handle both cases. + auto *BaseLoc = cast_or_null<AggregateStorageLocation>( + Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer)); + if (BaseLoc == nullptr) + return; + + // FIXME: Add support for union types. + if (BaseLoc->getType()->isUnionType()) + return; + + auto &MemberLoc = BaseLoc->getChild(*Member); + if (MemberLoc.getType()->isReferenceType()) { + Env.setStorageLocation(*S, MemberLoc); + } else { + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + Env.setValue( + Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc))); + } + } + + void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { + const Expr *InitExpr = S->getExpr(); + assert(InitExpr != nullptr); + + Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None); + if (InitExprVal == nullptr) + return; + + const FieldDecl *Field = S->getField(); + assert(Field != nullptr); + + auto &ThisLoc = + *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation()); + auto &FieldLoc = ThisLoc.getChild(*Field); + Env.setValue(FieldLoc, *InitExprVal); + } + + void VisitCXXConstructExpr(const CXXConstructExpr *S) { + const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); + assert(ConstructorDecl != nullptr); + + if (ConstructorDecl->isCopyOrMoveConstructor()) { + assert(S->getNumArgs() == 1); + + const Expr *Arg = S->getArg(0); + assert(Arg != nullptr); + + if (S->isElidable()) { + auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference); + if (ArgLoc == nullptr) + return; + + Env.setStorageLocation(*S, *ArgLoc); + } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) { + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + Env.setValue(Loc, *ArgVal); + } + return; + } + + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + if (Value *Val = Env.createValue(S->getType())) + Env.setValue(Loc, *Val); + } + + void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { + if (S->getOperator() == OO_Equal) { + assert(S->getNumArgs() == 2); + + const Expr *Arg0 = S->getArg(0); + assert(Arg0 != nullptr); + + const Expr *Arg1 = S->getArg(1); + assert(Arg1 != nullptr); + + // Evaluate only copy and move assignment operators. + auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType(); + auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType(); + if (Arg0Type != Arg1Type) + return; + + auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference); + if (ObjectLoc == nullptr) + return; + + auto *Val = Env.getValue(*Arg1, SkipPast::Reference); + if (Val == nullptr) + return; + + Env.setValue(*ObjectLoc, *Val); + } + } + + void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { + if (S->getCastKind() == CK_ConstructorConversion) { + // The CFG does not contain `ParenExpr` as top-level statements in basic + // blocks, however sub-expressions can still be of that type. + assert(S->getSubExpr() != nullptr); + const Expr *SubExpr = S->getSubExpr(); + assert(SubExpr != nullptr); + + auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); + if (SubExprLoc == nullptr) + return; + + Env.setStorageLocation(*S, *SubExprLoc); + } + } + + void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + if (Value *Val = Env.createValue(S->getType())) + Env.setValue(Loc, *Val); + } + + void VisitCallExpr(const CallExpr *S) { + if (S->isCallToStdMove()) { + assert(S->getNumArgs() == 1); + + const Expr *Arg = S->getArg(0); + assert(Arg != nullptr); + + auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None); + if (ArgLoc == nullptr) + return; + + Env.setStorageLocation(*S, *ArgLoc); + } + } + + void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { + const Expr *SubExpr = S->getSubExpr(); + assert(SubExpr != nullptr); + + auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); + if (SubExprLoc == nullptr) + return; + + Env.setStorageLocation(*S, *SubExprLoc); + } + + void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { + const Expr *SubExpr = S->getSubExpr(); + assert(SubExpr != nullptr); + + auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); + if (SubExprLoc == nullptr) + return; + + Env.setStorageLocation(*S, *SubExprLoc); + } + + void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { + if (S->getCastKind() == CK_NoOp) { + const Expr *SubExpr = S->getSubExpr(); + assert(SubExpr != nullptr); + + auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); + if (SubExprLoc == nullptr) + return; + + Env.setStorageLocation(*S, *SubExprLoc); + } + } + + void VisitConditionalOperator(const ConditionalOperator *S) { + // FIXME: Revisit this once flow conditions are added to the framework. For + // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow + // condition. + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + if (Value *Val = Env.createValue(S->getType())) + Env.setValue(Loc, *Val); + } + + void VisitInitListExpr(const InitListExpr *S) { + QualType Type = S->getType(); + + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + + auto *Val = Env.createValue(Type); + if (Val == nullptr) + return; + + Env.setValue(Loc, *Val); + + if (Type->isStructureOrClassType()) { + for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) { + const FieldDecl *Field = std::get<0>(IT); + assert(Field != nullptr); + + const Expr *Init = std::get<1>(IT); + assert(Init != nullptr); + + if (Value *InitVal = Env.getValue(*Init, SkipPast::None)) + cast<StructValue>(Val)->setChild(*Field, *InitVal); + } + } + // FIXME: Implement array initialization. + } + + void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { + auto &Loc = Env.createStorageLocation(*S); + Env.setStorageLocation(*S, Loc); + Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue())); + } + +private: + Environment &Env; +}; + +void transfer(const Stmt &S, Environment &Env) { + assert(!isa<ParenExpr>(&S)); + TransferVisitor(Env).Visit(&S); +} + +} // namespace dataflow +} // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 413e8d14bf0a..aaf6a834f5b3 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -11,14 +11,19 @@ // //===----------------------------------------------------------------------===// +#include <memory> #include <utility> #include <vector> +#include "clang/AST/DeclCXX.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/DataflowWorklist.h" +#include "clang/Analysis/FlowSensitive/Transfer.h" #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" +#include "clang/Analysis/FlowSensitive/Value.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/raw_ostream.h" @@ -35,15 +40,44 @@ namespace dataflow { /// already been transferred. States in `BlockStates` that are set to /// `llvm::None` represent basic blocks that are not evaluated yet. static TypeErasedDataflowAnalysisState computeBlockInputState( + const ControlFlowContext &CFCtx, std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> &BlockStates, const CFGBlock &Block, const Environment &InitEnv, TypeErasedDataflowAnalysis &Analysis) { - // FIXME: Consider passing `Block` to `Analysis.typeErasedInitialElement()` - // to enable building analyses like computation of dominators that initialize - // the state of each basic block differently. - TypeErasedDataflowAnalysisState State = {Analysis.typeErasedInitialElement(), - InitEnv}; - for (const CFGBlock *Pred : Block.preds()) { + llvm::DenseSet<const CFGBlock *> Preds; + Preds.insert(Block.pred_begin(), Block.pred_end()); + if (Block.getTerminator().isTemporaryDtorsBranch()) { + // This handles a special case where the code that produced the CFG includes + // a conditional operator with a branch that constructs a temporary and + // calls a destructor annotated as noreturn. The CFG models this as follows: + // + // B1 (contains the condition of the conditional operator) - succs: B2, B3 + // B2 (contains code that does not call a noreturn destructor) - succs: B4 + // B3 (contains code that calls a noreturn destructor) - succs: B4 + // B4 (has temporary destructor terminator) - succs: B5, B6 + // B5 (noreturn block that is associated with the noreturn destructor call) + // B6 (contains code that follows the conditional operator statement) + // + // The first successor (B5 above) of a basic block with a temporary + // destructor terminator (B4 above) is the block that evaluates the + // destructor. If that block has a noreturn element then the predecessor + // block that constructed the temporary object (B3 above) is effectively a + // noreturn block and its state should not be used as input for the state + // of the block that has a temporary destructor terminator (B4 above). This + // holds regardless of which branch of the ternary operator calls the + // noreturn destructor. However, it doesn't cases where a nested ternary + // operator includes a branch that contains a noreturn destructor call. + // + // See `NoreturnDestructorTest` for concrete examples. + if (Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) { + auto StmtBlock = CFCtx.getStmtToBlock().find(Block.getTerminatorStmt()); + assert(StmtBlock != CFCtx.getStmtToBlock().end()); + Preds.erase(StmtBlock->getSecond()); + } + } + + llvm::Optional<TypeErasedDataflowAnalysisState> MaybeState; + for (const CFGBlock *Pred : Preds) { // Skip if the `Block` is unreachable or control flow cannot get past it. if (!Pred || Pred->hasNoReturnElement()) continue; @@ -57,13 +91,79 @@ static TypeErasedDataflowAnalysisState computeBlockInputState( const TypeErasedDataflowAnalysisState &PredState = MaybePredState.getValue(); - Analysis.joinTypeErased(State.Lattice, PredState.Lattice); - State.Env.join(PredState.Env); + if (MaybeState.hasValue()) { + Analysis.joinTypeErased(MaybeState->Lattice, PredState.Lattice); + MaybeState->Env.join(PredState.Env, Analysis); + } else { + MaybeState = PredState; + } + } + if (!MaybeState.hasValue()) { + // FIXME: Consider passing `Block` to `Analysis.typeErasedInitialElement()` + // to enable building analyses like computation of dominators that + // initialize the state of each basic block differently. + MaybeState.emplace(Analysis.typeErasedInitialElement(), InitEnv); + } + return *MaybeState; +} + +/// Transfers `State` by evaluating `CfgStmt` in the context of `Analysis`. +/// `HandleTransferredStmt` (if provided) will be applied to `CfgStmt`, after it +/// is evaluated. +static void +transferCFGStmt(const CFGStmt &CfgStmt, TypeErasedDataflowAnalysis &Analysis, + TypeErasedDataflowAnalysisState &State, + std::function<void(const CFGStmt &, + const TypeErasedDataflowAnalysisState &)> + HandleTransferredStmt) { + const Stmt *S = CfgStmt.getStmt(); + assert(S != nullptr); + + if (Analysis.applyBuiltinTransfer()) + transfer(*S, State.Env); + Analysis.transferTypeErased(S, State.Lattice, State.Env); + + if (HandleTransferredStmt != nullptr) + HandleTransferredStmt(CfgStmt, State); +} + +/// Transfers `State` by evaluating `CfgInit`. +static void transferCFGInitializer(const CFGInitializer &CfgInit, + TypeErasedDataflowAnalysisState &State) { + const auto &ThisLoc = *cast<AggregateStorageLocation>( + State.Env.getThisPointeeStorageLocation()); + + const CXXCtorInitializer *Initializer = CfgInit.getInitializer(); + assert(Initializer != nullptr); + + auto *InitStmt = Initializer->getInit(); + assert(InitStmt != nullptr); + + auto *InitStmtLoc = + State.Env.getStorageLocation(*InitStmt, SkipPast::Reference); + if (InitStmtLoc == nullptr) + return; + + auto *InitStmtVal = State.Env.getValue(*InitStmtLoc); + if (InitStmtVal == nullptr) + return; + + const FieldDecl *Member = Initializer->getMember(); + assert(Member != nullptr); + + if (Member->getType()->isReferenceType()) { + auto &MemberLoc = ThisLoc.getChild(*Member); + State.Env.setValue(MemberLoc, + State.Env.takeOwnership( + std::make_unique<ReferenceValue>(*InitStmtLoc))); + } else { + auto &MemberLoc = ThisLoc.getChild(*Member); + State.Env.setValue(MemberLoc, *InitStmtVal); } - return State; } TypeErasedDataflowAnalysisState transferBlock( + const ControlFlowContext &CFCtx, std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> &BlockStates, const CFGBlock &Block, const Environment &InitEnv, TypeErasedDataflowAnalysis &Analysis, @@ -71,39 +171,37 @@ TypeErasedDataflowAnalysisState transferBlock( const TypeErasedDataflowAnalysisState &)> HandleTransferredStmt) { TypeErasedDataflowAnalysisState State = - computeBlockInputState(BlockStates, Block, InitEnv, Analysis); + computeBlockInputState(CFCtx, BlockStates, Block, InitEnv, Analysis); for (const CFGElement &Element : Block) { - // FIXME: Evaluate other kinds of `CFGElement`. - const llvm::Optional<CFGStmt> Stmt = Element.getAs<CFGStmt>(); - if (!Stmt.hasValue()) - continue; - - // FIXME: Evaluate the statement contained in `Stmt`. - - State.Lattice = Analysis.transferTypeErased(Stmt.getValue().getStmt(), - State.Lattice, State.Env); - if (HandleTransferredStmt != nullptr) - HandleTransferredStmt(Stmt.getValue(), State); + switch (Element.getKind()) { + case CFGElement::Statement: + transferCFGStmt(*Element.getAs<CFGStmt>(), Analysis, State, + HandleTransferredStmt); + break; + case CFGElement::Initializer: + if (Analysis.applyBuiltinTransfer()) + transferCFGInitializer(*Element.getAs<CFGInitializer>(), State); + break; + default: + // FIXME: Evaluate other kinds of `CFGElement`. + break; + } } return State; } std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> -runTypeErasedDataflowAnalysis(const CFG &Cfg, +runTypeErasedDataflowAnalysis(const ControlFlowContext &CFCtx, TypeErasedDataflowAnalysis &Analysis, const Environment &InitEnv) { - // FIXME: Consider enforcing that `Cfg` meets the requirements that - // are specified in the header. This could be done by remembering - // what options were used to build `Cfg` and asserting on them here. - - PostOrderCFGView POV(&Cfg); - ForwardDataflowWorklist Worklist(Cfg, &POV); + PostOrderCFGView POV(&CFCtx.getCFG()); + ForwardDataflowWorklist Worklist(CFCtx.getCFG(), &POV); std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockStates; - BlockStates.resize(Cfg.size(), llvm::None); + BlockStates.resize(CFCtx.getCFG().size(), llvm::None); // The entry basic block doesn't contain statements so it can be skipped. - const CFGBlock &Entry = Cfg.getEntry(); + const CFGBlock &Entry = CFCtx.getCFG().getEntry(); BlockStates[Entry.getBlockID()] = {Analysis.typeErasedInitialElement(), InitEnv}; Worklist.enqueueSuccessors(&Entry); @@ -114,8 +212,8 @@ runTypeErasedDataflowAnalysis(const CFG &Cfg, // FIXME: Consider making the maximum number of iterations configurable. // FIXME: Set up statistics (see llvm/ADT/Statistic.h) to count average number // of iterations, number of functions that time out, etc. - unsigned Iterations = 0; - static constexpr unsigned MaxIterations = 1 << 16; + uint32_t Iterations = 0; + static constexpr uint32_t MaxIterations = 1 << 16; while (const CFGBlock *Block = Worklist.dequeue()) { if (++Iterations > MaxIterations) { llvm::errs() << "Maximum number of iterations reached, giving up.\n"; @@ -125,7 +223,7 @@ runTypeErasedDataflowAnalysis(const CFG &Cfg, const llvm::Optional<TypeErasedDataflowAnalysisState> &OldBlockState = BlockStates[Block->getBlockID()]; TypeErasedDataflowAnalysisState NewBlockState = - transferBlock(BlockStates, *Block, InitEnv, Analysis); + transferBlock(CFCtx, BlockStates, *Block, InitEnv, Analysis); if (OldBlockState.hasValue() && Analysis.isEqualTypeErased(OldBlockState.getValue().Lattice, diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp index a38ae34f4b81..811146e50b45 100644 --- a/clang/lib/Analysis/UninitializedValues.cpp +++ b/clang/lib/Analysis/UninitializedValues.cpp @@ -819,12 +819,11 @@ void TransferFunctions::VisitGCCAsmStmt(GCCAsmStmt *as) { while (const auto *UO = dyn_cast<UnaryOperator>(Ex)) Ex = stripCasts(C, UO->getSubExpr()); + // Mark the variable as potentially uninitialized for those cases where + // it's used on an indirect path, where it's not guaranteed to be + // defined. if (const VarDecl *VD = findVar(Ex).getDecl()) - if (vals[VD] != Initialized) - // If the variable isn't initialized by the time we get here, then we - // mark it as potentially uninitialized for those cases where it's used - // on an indirect path, where it's not guaranteed to be defined. - vals[VD] = MayUninitialized; + vals[VD] = MayUninitialized; } } diff --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp index fe35f77782c9..64bcb45a4cd8 100644 --- a/clang/lib/Basic/DarwinSDKInfo.cpp +++ b/clang/lib/Basic/DarwinSDKInfo.cpp @@ -84,6 +84,25 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) { llvm::DenseMap<OSEnvPair::StorageType, Optional<RelatedTargetVersionMapping>> VersionMappings; if (const auto *VM = Obj->getObject("VersionMap")) { + // FIXME: Generalize this out beyond iOS-deriving targets. + // Look for ios_<targetos> version mapping for targets that derive from ios. + for (const auto &KV : *VM) { + auto Pair = StringRef(KV.getFirst()).split("_"); + if (Pair.first.compare_insensitive("ios") == 0) { + llvm::Triple TT(llvm::Twine("--") + Pair.second.lower()); + if (TT.getOS() != llvm::Triple::UnknownOS) { + auto Mapping = RelatedTargetVersionMapping::parseJSON( + *KV.getSecond().getAsObject(), *MaximumDeploymentVersion); + if (Mapping) + VersionMappings[OSEnvPair(llvm::Triple::IOS, + llvm::Triple::UnknownEnvironment, + TT.getOS(), + llvm::Triple::UnknownEnvironment) + .Value] = std::move(Mapping); + } + } + } + if (const auto *Mapping = VM->getObject("macOS_iOSMac")) { auto VersionMap = RelatedTargetVersionMapping::parseJSON( *Mapping, *MaximumDeploymentVersion); diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index 9b7ad96b949f..ac4b9d2cd5a2 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -374,6 +374,12 @@ void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map, DiagnosticMapping Mapping = makeUserMapping(Map, L); Mapping.setUpgradedFromWarning(WasUpgradedFromWarning); + // Make sure we propagate the NoWarningAsError flag from an existing + // mapping (which may be the default mapping). + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); + Mapping.setNoWarningAsError(Info.hasNoWarningAsError() || + Mapping.hasNoWarningAsError()); + // Common case; setting all the diagnostics of a group in one place. if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) && DiagStatesByLoc.getCurDiagState()) { diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp index a9f2d09924cd..87db131992e4 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -33,7 +33,7 @@ struct StaticDiagInfoRec; // platforms. See "How To Write Shared Libraries" by Ulrich Drepper. struct StaticDiagInfoDescriptionStringTable { #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ char ENUM##_desc[sizeof(DESC)]; // clang-format off #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -54,7 +54,7 @@ struct StaticDiagInfoDescriptionStringTable { const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = { #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ DESC, // clang-format off #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -79,7 +79,7 @@ extern const StaticDiagInfoRec StaticDiagInfo[]; // StaticDiagInfoRec would have extra padding on 64-bit platforms. const uint32_t StaticDiagInfoDescriptionOffsets[] = { #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc), // clang-format off #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -115,6 +115,7 @@ struct StaticDiagInfoRec { uint8_t Category : 6; uint8_t WarnNoWerror : 1; uint8_t WarnShowInSystemHeader : 1; + uint8_t WarnShowInSystemMacro : 1; uint16_t OptionGroupIndex : 15; uint16_t Deferrable : 1; @@ -170,7 +171,7 @@ VALIDATE_DIAG_SIZE(REFACTORING) const StaticDiagInfoRec StaticDiagInfo[] = { // clang-format off #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ { \ diag::ENUM, \ DEFAULT_SEVERITY, \ @@ -179,6 +180,7 @@ const StaticDiagInfoRec StaticDiagInfo[] = { CATEGORY, \ NOWERROR, \ SHOWINSYSHEADER, \ + SHOWINSYSMACRO, \ GROUP, \ DEFERRABLE, \ STR_SIZE(DESC, uint16_t)}, @@ -586,6 +588,13 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, Diag.getSourceManager().getExpansionLoc(Loc))) return diag::Severity::Ignored; + // We also ignore warnings due to system macros + bool ShowInSystemMacro = + !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemMacro; + if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() && + Diag.getSourceManager().isInSystemMacro(Loc)) + return diag::Severity::Ignored; + return Result; } diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index d811aeec84a0..b86cb7af69bd 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -309,6 +309,14 @@ IdentifierInfo::isReserved(const LangOptions &LangOpts) const { return ReservedIdentifierStatus::NotReserved; } +StringRef IdentifierInfo::deuglifiedName() const { + StringRef Name = getName(); + if (Name.size() >= 2 && Name.front() == '_' && + (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z'))) + return Name.ltrim('_'); + return Name; +} + tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { // We use a perfect hash function here involving the length of the keyword, // the first and third character. For preprocessor ID's there are no diff --git a/clang/lib/Basic/OpenCLOptions.cpp b/clang/lib/Basic/OpenCLOptions.cpp index b7408f39bdab..7e89b3f1b804 100644 --- a/clang/lib/Basic/OpenCLOptions.cpp +++ b/clang/lib/Basic/OpenCLOptions.cpp @@ -12,6 +12,17 @@ namespace clang { +const OpenCLOptions::FeatureDepList OpenCLOptions::DependentFeaturesList = { + {"__opencl_c_read_write_images", "__opencl_c_images"}, + {"__opencl_c_3d_image_writes", "__opencl_c_images"}, + {"__opencl_c_pipes", "__opencl_c_generic_address_space"}, + {"__opencl_c_device_enqueue", "__opencl_c_generic_address_space"}, + {"__opencl_c_device_enqueue", "__opencl_c_program_scope_global_variables"}}; + +const llvm::StringMap<llvm::StringRef> OpenCLOptions::FeatureExtensionMap = { + {"cl_khr_fp64", "__opencl_c_fp64"}, + {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}}; + bool OpenCLOptions::isKnown(llvm::StringRef Ext) const { return OptMap.find(Ext) != OptMap.end(); } @@ -108,33 +119,23 @@ void OpenCLOptions::disableAll() { bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies( const TargetInfo &TI, DiagnosticsEngine &Diags) { - // Feature pairs. First feature in a pair requires the second one to be - // supported. - static const llvm::StringMap<llvm::StringRef> DependentFeaturesMap = { - {"__opencl_c_read_write_images", "__opencl_c_images"}, - {"__opencl_c_3d_image_writes", "__opencl_c_images"}, - {"__opencl_c_pipes", "__opencl_c_generic_address_space"}}; - auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts(); bool IsValid = true; - for (auto &FeaturePair : DependentFeaturesMap) - if (TI.hasFeatureEnabled(OpenCLFeaturesMap, FeaturePair.getKey()) && - !TI.hasFeatureEnabled(OpenCLFeaturesMap, FeaturePair.getValue())) { + for (auto &FeaturePair : DependentFeaturesList) { + auto Feature = FeaturePair.first; + auto Dep = FeaturePair.second; + if (TI.hasFeatureEnabled(OpenCLFeaturesMap, Feature) && + !TI.hasFeatureEnabled(OpenCLFeaturesMap, Dep)) { IsValid = false; - Diags.Report(diag::err_opencl_feature_requires) - << FeaturePair.getKey() << FeaturePair.getValue(); + Diags.Report(diag::err_opencl_feature_requires) << Feature << Dep; } + } return IsValid; } bool OpenCLOptions::diagnoseFeatureExtensionDifferences( const TargetInfo &TI, DiagnosticsEngine &Diags) { - // Extensions and equivalent feature pairs. - static const llvm::StringMap<llvm::StringRef> FeatureExtensionMap = { - {"cl_khr_fp64", "__opencl_c_fp64"}, - {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}}; - auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts(); bool IsValid = true; diff --git a/clang/lib/Basic/TargetID.cpp b/clang/lib/Basic/TargetID.cpp index 59d416f0e015..3b8f4c13b9bf 100644 --- a/clang/lib/Basic/TargetID.cpp +++ b/clang/lib/Basic/TargetID.cpp @@ -15,7 +15,7 @@ namespace clang { -static const llvm::SmallVector<llvm::StringRef, 4> +static llvm::SmallVector<llvm::StringRef, 4> getAllPossibleAMDGPUTargetIDFeatures(const llvm::Triple &T, llvm::StringRef Proc) { // Entries in returned vector should be in alphabetical order. @@ -33,7 +33,7 @@ getAllPossibleAMDGPUTargetIDFeatures(const llvm::Triple &T, return Ret; } -const llvm::SmallVector<llvm::StringRef, 4> +llvm::SmallVector<llvm::StringRef, 4> getAllPossibleTargetIDFeatures(const llvm::Triple &T, llvm::StringRef Processor) { llvm::SmallVector<llvm::StringRef, 4> Ret; diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 646bbe8b7387..e3a2f30febe7 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -25,7 +25,7 @@ using namespace clang; static const LangASMap DefaultAddrSpaceMap = {0}; // TargetInfo Constructor. -TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { +TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or // SPARC. These should be overridden by concrete targets as needed. BigEndian = !T.isLittleEndian(); @@ -150,6 +150,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { PlatformMinVersion = VersionTuple(); MaxOpenCLWorkGroupSize = 1024; + ProgramAddrSpace = 0; } // Out of line virtual dtor for TargetInfo. @@ -421,6 +422,8 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { OpenCLFeaturesMap, "__opencl_c_generic_address_space"); Opts.OpenCLPipes = hasFeatureEnabled(OpenCLFeaturesMap, "__opencl_c_pipes"); + Opts.Blocks = + hasFeatureEnabled(OpenCLFeaturesMap, "__opencl_c_device_enqueue"); } } diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 4089a393b762..8e23cc4c421a 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -45,6 +45,7 @@ static StringRef getArchVersionString(llvm::AArch64::ArchKind Kind) { case llvm::AArch64::ArchKind::ARMV9A: case llvm::AArch64::ArchKind::ARMV9_1A: case llvm::AArch64::ArchKind::ARMV9_2A: + case llvm::AArch64::ArchKind::ARMV9_3A: return "9"; default: return "8"; @@ -223,6 +224,12 @@ void AArch64TargetInfo::getTargetDefinesARMV87A(const LangOptions &Opts, getTargetDefinesARMV86A(Opts, Builder); } +void AArch64TargetInfo::getTargetDefinesARMV88A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the Armv8.7 defines + getTargetDefinesARMV87A(Opts, Builder); +} + void AArch64TargetInfo::getTargetDefinesARMV9A(const LangOptions &Opts, MacroBuilder &Builder) const { // Armv9-A maps to Armv8.5-A @@ -241,6 +248,12 @@ void AArch64TargetInfo::getTargetDefinesARMV92A(const LangOptions &Opts, getTargetDefinesARMV87A(Opts, Builder); } +void AArch64TargetInfo::getTargetDefinesARMV93A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Armv9.3-A maps to Armv8.8-A + getTargetDefinesARMV88A(Opts, Builder); +} + void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. @@ -446,6 +459,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, case llvm::AArch64::ArchKind::ARMV8_7A: getTargetDefinesARMV87A(Opts, Builder); break; + case llvm::AArch64::ArchKind::ARMV8_8A: + getTargetDefinesARMV88A(Opts, Builder); + break; case llvm::AArch64::ArchKind::ARMV9A: getTargetDefinesARMV9A(Opts, Builder); break; @@ -455,6 +471,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, case llvm::AArch64::ArchKind::ARMV9_2A: getTargetDefinesARMV92A(Opts, Builder); break; + case llvm::AArch64::ArchKind::ARMV9_3A: + getTargetDefinesARMV93A(Opts, Builder); + break; } // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. @@ -524,6 +543,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, HasMatmulFP64 = false; HasMatmulFP32 = false; HasLSE = false; + HasHBC = false; + HasMOPS = false; ArchKind = llvm::AArch64::ArchKind::INVALID; @@ -532,36 +553,36 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, FPU |= NeonMode; if (Feature == "+sve") { FPU |= SveMode; - HasFullFP16 = 1; + HasFullFP16 = true; } if (Feature == "+sve2") { FPU |= SveMode; - HasFullFP16 = 1; - HasSVE2 = 1; + HasFullFP16 = true; + HasSVE2 = true; } if (Feature == "+sve2-aes") { FPU |= SveMode; - HasFullFP16 = 1; - HasSVE2 = 1; - HasSVE2AES = 1; + HasFullFP16 = true; + HasSVE2 = true; + HasSVE2AES = true; } if (Feature == "+sve2-sha3") { FPU |= SveMode; - HasFullFP16 = 1; - HasSVE2 = 1; - HasSVE2SHA3 = 1; + HasFullFP16 = true; + HasSVE2 = true; + HasSVE2SHA3 = true; } if (Feature == "+sve2-sm4") { FPU |= SveMode; - HasFullFP16 = 1; - HasSVE2 = 1; - HasSVE2SM4 = 1; + HasFullFP16 = true; + HasSVE2 = true; + HasSVE2SM4 = true; } if (Feature == "+sve2-bitperm") { FPU |= SveMode; - HasFullFP16 = 1; - HasSVE2 = 1; - HasSVE2BitPerm = 1; + HasFullFP16 = true; + HasSVE2 = true; + HasSVE2BitPerm = true; } if (Feature == "+f32mm") { FPU |= SveMode; @@ -603,12 +624,16 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, ArchKind = llvm::AArch64::ArchKind::ARMV8_6A; if (Feature == "+v8.7a") ArchKind = llvm::AArch64::ArchKind::ARMV8_7A; + if (Feature == "+v8.8a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_8A; if (Feature == "+v9a") ArchKind = llvm::AArch64::ArchKind::ARMV9A; if (Feature == "+v9.1a") ArchKind = llvm::AArch64::ArchKind::ARMV9_1A; if (Feature == "+v9.2a") ArchKind = llvm::AArch64::ArchKind::ARMV9_2A; + if (Feature == "+v9.3a") + ArchKind = llvm::AArch64::ArchKind::ARMV9_3A; if (Feature == "+v8r") ArchKind = llvm::AArch64::ArchKind::ARMV8R; if (Feature == "+fullfp16") @@ -635,6 +660,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, HasRandGen = true; if (Feature == "+flagm") HasFlagM = true; + if (Feature == "+hbc") + HasHBC = true; } setDataLayout(); diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 74745df3be8d..ebddce0c1c73 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -15,6 +15,7 @@ #include "OSTargets.h" #include "clang/Basic/TargetBuiltins.h" +#include "llvm/Support/AArch64TargetParser.h" #include "llvm/Support/TargetParser.h" namespace clang { @@ -53,6 +54,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { bool HasMatmulFP32; bool HasLSE; bool HasFlagM; + bool HasHBC; + bool HasMOPS; llvm::AArch64::ArchKind ArchKind; @@ -92,12 +95,16 @@ public: MacroBuilder &Builder) const; void getTargetDefinesARMV87A(const LangOptions &Opts, MacroBuilder &Builder) const; + void getTargetDefinesARMV88A(const LangOptions &Opts, + MacroBuilder &Builder) const; void getTargetDefinesARMV9A(const LangOptions &Opts, MacroBuilder &Builder) const; void getTargetDefinesARMV91A(const LangOptions &Opts, MacroBuilder &Builder) const; void getTargetDefinesARMV92A(const LangOptions &Opts, MacroBuilder &Builder) const; + void getTargetDefinesARMV93A(const LangOptions &Opts, + MacroBuilder &Builder) const; void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index c619d6cde41d..478a0233398d 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -212,12 +212,16 @@ StringRef ARMTargetInfo::getCPUAttr() const { return "8_6A"; case llvm::ARM::ArchKind::ARMV8_7A: return "8_7A"; + case llvm::ARM::ArchKind::ARMV8_8A: + return "8_8A"; case llvm::ARM::ArchKind::ARMV9A: return "9A"; case llvm::ARM::ArchKind::ARMV9_1A: return "9_1A"; case llvm::ARM::ArchKind::ARMV9_2A: return "9_2A"; + case llvm::ARM::ArchKind::ARMV9_3A: + return "9_3A"; case llvm::ARM::ArchKind::ARMV8MBaseline: return "8M_BASE"; case llvm::ARM::ArchKind::ARMV8MMainline: @@ -930,9 +934,11 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, case llvm::ARM::ArchKind::ARMV8_4A: case llvm::ARM::ArchKind::ARMV8_5A: case llvm::ARM::ArchKind::ARMV8_6A: + case llvm::ARM::ArchKind::ARMV8_8A: case llvm::ARM::ArchKind::ARMV9A: case llvm::ARM::ArchKind::ARMV9_1A: case llvm::ARM::ArchKind::ARMV9_2A: + case llvm::ARM::ArchKind::ARMV9_3A: getTargetDefinesARMV83A(Opts, Builder); break; } diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index 40c658f3f40e..f074dac57f9b 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -18,6 +18,7 @@ #include "clang/Basic/TargetOptions.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/ARMTargetParser.h" #include "llvm/Support/TargetParser.h" namespace clang { diff --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp index 50b0fc07b311..6266ed72cd5c 100644 --- a/clang/lib/Basic/Targets/AVR.cpp +++ b/clang/lib/Basic/Targets/AVR.cpp @@ -24,281 +24,282 @@ namespace targets { struct LLVM_LIBRARY_VISIBILITY MCUInfo { const char *Name; const char *DefineName; + const int NumFlashBanks; // -1 means the device does not support LPM/ELPM. }; // This list should be kept up-to-date with AVRDevices.td in LLVM. static MCUInfo AVRMcus[] = { - {"at90s1200", "__AVR_AT90S1200__"}, - {"attiny11", "__AVR_ATtiny11__"}, - {"attiny12", "__AVR_ATtiny12__"}, - {"attiny15", "__AVR_ATtiny15__"}, - {"attiny28", "__AVR_ATtiny28__"}, - {"at90s2313", "__AVR_AT90S2313__"}, - {"at90s2323", "__AVR_AT90S2323__"}, - {"at90s2333", "__AVR_AT90S2333__"}, - {"at90s2343", "__AVR_AT90S2343__"}, - {"attiny22", "__AVR_ATtiny22__"}, - {"attiny26", "__AVR_ATtiny26__"}, - {"at86rf401", "__AVR_AT86RF401__"}, - {"at90s4414", "__AVR_AT90S4414__"}, - {"at90s4433", "__AVR_AT90S4433__"}, - {"at90s4434", "__AVR_AT90S4434__"}, - {"at90s8515", "__AVR_AT90S8515__"}, - {"at90c8534", "__AVR_AT90c8534__"}, - {"at90s8535", "__AVR_AT90S8535__"}, - {"ata5272", "__AVR_ATA5272__"}, - {"attiny13", "__AVR_ATtiny13__"}, - {"attiny13a", "__AVR_ATtiny13A__"}, - {"attiny2313", "__AVR_ATtiny2313__"}, - {"attiny2313a", "__AVR_ATtiny2313A__"}, - {"attiny24", "__AVR_ATtiny24__"}, - {"attiny24a", "__AVR_ATtiny24A__"}, - {"attiny4313", "__AVR_ATtiny4313__"}, - {"attiny44", "__AVR_ATtiny44__"}, - {"attiny44a", "__AVR_ATtiny44A__"}, - {"attiny84", "__AVR_ATtiny84__"}, - {"attiny84a", "__AVR_ATtiny84A__"}, - {"attiny25", "__AVR_ATtiny25__"}, - {"attiny45", "__AVR_ATtiny45__"}, - {"attiny85", "__AVR_ATtiny85__"}, - {"attiny261", "__AVR_ATtiny261__"}, - {"attiny261a", "__AVR_ATtiny261A__"}, - {"attiny441", "__AVR_ATtiny441__"}, - {"attiny461", "__AVR_ATtiny461__"}, - {"attiny461a", "__AVR_ATtiny461A__"}, - {"attiny841", "__AVR_ATtiny841__"}, - {"attiny861", "__AVR_ATtiny861__"}, - {"attiny861a", "__AVR_ATtiny861A__"}, - {"attiny87", "__AVR_ATtiny87__"}, - {"attiny43u", "__AVR_ATtiny43U__"}, - {"attiny48", "__AVR_ATtiny48__"}, - {"attiny88", "__AVR_ATtiny88__"}, - {"attiny828", "__AVR_ATtiny828__"}, - {"at43usb355", "__AVR_AT43USB355__"}, - {"at76c711", "__AVR_AT76C711__"}, - {"atmega103", "__AVR_ATmega103__"}, - {"at43usb320", "__AVR_AT43USB320__"}, - {"attiny167", "__AVR_ATtiny167__"}, - {"at90usb82", "__AVR_AT90USB82__"}, - {"at90usb162", "__AVR_AT90USB162__"}, - {"ata5505", "__AVR_ATA5505__"}, - {"atmega8u2", "__AVR_ATmega8U2__"}, - {"atmega16u2", "__AVR_ATmega16U2__"}, - {"atmega32u2", "__AVR_ATmega32U2__"}, - {"attiny1634", "__AVR_ATtiny1634__"}, - {"atmega8", "__AVR_ATmega8__"}, - {"ata6289", "__AVR_ATA6289__"}, - {"atmega8a", "__AVR_ATmega8A__"}, - {"ata6285", "__AVR_ATA6285__"}, - {"ata6286", "__AVR_ATA6286__"}, - {"atmega48", "__AVR_ATmega48__"}, - {"atmega48a", "__AVR_ATmega48A__"}, - {"atmega48pa", "__AVR_ATmega48PA__"}, - {"atmega48pb", "__AVR_ATmega48PB__"}, - {"atmega48p", "__AVR_ATmega48P__"}, - {"atmega88", "__AVR_ATmega88__"}, - {"atmega88a", "__AVR_ATmega88A__"}, - {"atmega88p", "__AVR_ATmega88P__"}, - {"atmega88pa", "__AVR_ATmega88PA__"}, - {"atmega88pb", "__AVR_ATmega88PB__"}, - {"atmega8515", "__AVR_ATmega8515__"}, - {"atmega8535", "__AVR_ATmega8535__"}, - {"atmega8hva", "__AVR_ATmega8HVA__"}, - {"at90pwm1", "__AVR_AT90PWM1__"}, - {"at90pwm2", "__AVR_AT90PWM2__"}, - {"at90pwm2b", "__AVR_AT90PWM2B__"}, - {"at90pwm3", "__AVR_AT90PWM3__"}, - {"at90pwm3b", "__AVR_AT90PWM3B__"}, - {"at90pwm81", "__AVR_AT90PWM81__"}, - {"ata5790", "__AVR_ATA5790__"}, - {"ata5795", "__AVR_ATA5795__"}, - {"atmega16", "__AVR_ATmega16__"}, - {"atmega16a", "__AVR_ATmega16A__"}, - {"atmega161", "__AVR_ATmega161__"}, - {"atmega162", "__AVR_ATmega162__"}, - {"atmega163", "__AVR_ATmega163__"}, - {"atmega164a", "__AVR_ATmega164A__"}, - {"atmega164p", "__AVR_ATmega164P__"}, - {"atmega164pa", "__AVR_ATmega164PA__"}, - {"atmega165", "__AVR_ATmega165__"}, - {"atmega165a", "__AVR_ATmega165A__"}, - {"atmega165p", "__AVR_ATmega165P__"}, - {"atmega165pa", "__AVR_ATmega165PA__"}, - {"atmega168", "__AVR_ATmega168__"}, - {"atmega168a", "__AVR_ATmega168A__"}, - {"atmega168p", "__AVR_ATmega168P__"}, - {"atmega168pa", "__AVR_ATmega168PA__"}, - {"atmega168pb", "__AVR_ATmega168PB__"}, - {"atmega169", "__AVR_ATmega169__"}, - {"atmega169a", "__AVR_ATmega169A__"}, - {"atmega169p", "__AVR_ATmega169P__"}, - {"atmega169pa", "__AVR_ATmega169PA__"}, - {"atmega32", "__AVR_ATmega32__"}, - {"atmega32a", "__AVR_ATmega32A__"}, - {"atmega323", "__AVR_ATmega323__"}, - {"atmega324a", "__AVR_ATmega324A__"}, - {"atmega324p", "__AVR_ATmega324P__"}, - {"atmega324pa", "__AVR_ATmega324PA__"}, - {"atmega324pb", "__AVR_ATmega324PB__"}, - {"atmega325", "__AVR_ATmega325__"}, - {"atmega325a", "__AVR_ATmega325A__"}, - {"atmega325p", "__AVR_ATmega325P__"}, - {"atmega325pa", "__AVR_ATmega325PA__"}, - {"atmega3250", "__AVR_ATmega3250__"}, - {"atmega3250a", "__AVR_ATmega3250A__"}, - {"atmega3250p", "__AVR_ATmega3250P__"}, - {"atmega3250pa", "__AVR_ATmega3250PA__"}, - {"atmega328", "__AVR_ATmega328__"}, - {"atmega328p", "__AVR_ATmega328P__"}, - {"atmega328pb", "__AVR_ATmega328PB__"}, - {"atmega329", "__AVR_ATmega329__"}, - {"atmega329a", "__AVR_ATmega329A__"}, - {"atmega329p", "__AVR_ATmega329P__"}, - {"atmega329pa", "__AVR_ATmega329PA__"}, - {"atmega3290", "__AVR_ATmega3290__"}, - {"atmega3290a", "__AVR_ATmega3290A__"}, - {"atmega3290p", "__AVR_ATmega3290P__"}, - {"atmega3290pa", "__AVR_ATmega3290PA__"}, - {"atmega406", "__AVR_ATmega406__"}, - {"atmega64", "__AVR_ATmega64__"}, - {"atmega64a", "__AVR_ATmega64A__"}, - {"atmega640", "__AVR_ATmega640__"}, - {"atmega644", "__AVR_ATmega644__"}, - {"atmega644a", "__AVR_ATmega644A__"}, - {"atmega644p", "__AVR_ATmega644P__"}, - {"atmega644pa", "__AVR_ATmega644PA__"}, - {"atmega645", "__AVR_ATmega645__"}, - {"atmega645a", "__AVR_ATmega645A__"}, - {"atmega645p", "__AVR_ATmega645P__"}, - {"atmega649", "__AVR_ATmega649__"}, - {"atmega649a", "__AVR_ATmega649A__"}, - {"atmega649p", "__AVR_ATmega649P__"}, - {"atmega6450", "__AVR_ATmega6450__"}, - {"atmega6450a", "__AVR_ATmega6450A__"}, - {"atmega6450p", "__AVR_ATmega6450P__"}, - {"atmega6490", "__AVR_ATmega6490__"}, - {"atmega6490a", "__AVR_ATmega6490A__"}, - {"atmega6490p", "__AVR_ATmega6490P__"}, - {"atmega64rfr2", "__AVR_ATmega64RFR2__"}, - {"atmega644rfr2", "__AVR_ATmega644RFR2__"}, - {"atmega16hva", "__AVR_ATmega16HVA__"}, - {"atmega16hva2", "__AVR_ATmega16HVA2__"}, - {"atmega16hvb", "__AVR_ATmega16HVB__"}, - {"atmega16hvbrevb", "__AVR_ATmega16HVBREVB__"}, - {"atmega32hvb", "__AVR_ATmega32HVB__"}, - {"atmega32hvbrevb", "__AVR_ATmega32HVBREVB__"}, - {"atmega64hve", "__AVR_ATmega64HVE__"}, - {"at90can32", "__AVR_AT90CAN32__"}, - {"at90can64", "__AVR_AT90CAN64__"}, - {"at90pwm161", "__AVR_AT90PWM161__"}, - {"at90pwm216", "__AVR_AT90PWM216__"}, - {"at90pwm316", "__AVR_AT90PWM316__"}, - {"atmega32c1", "__AVR_ATmega32C1__"}, - {"atmega64c1", "__AVR_ATmega64C1__"}, - {"atmega16m1", "__AVR_ATmega16M1__"}, - {"atmega32m1", "__AVR_ATmega32M1__"}, - {"atmega64m1", "__AVR_ATmega64M1__"}, - {"atmega16u4", "__AVR_ATmega16U4__"}, - {"atmega32u4", "__AVR_ATmega32U4__"}, - {"atmega32u6", "__AVR_ATmega32U6__"}, - {"at90usb646", "__AVR_AT90USB646__"}, - {"at90usb647", "__AVR_AT90USB647__"}, - {"at90scr100", "__AVR_AT90SCR100__"}, - {"at94k", "__AVR_AT94K__"}, - {"m3000", "__AVR_AT000__"}, - {"atmega128", "__AVR_ATmega128__"}, - {"atmega128a", "__AVR_ATmega128A__"}, - {"atmega1280", "__AVR_ATmega1280__"}, - {"atmega1281", "__AVR_ATmega1281__"}, - {"atmega1284", "__AVR_ATmega1284__"}, - {"atmega1284p", "__AVR_ATmega1284P__"}, - {"atmega128rfa1", "__AVR_ATmega128RFA1__"}, - {"atmega128rfr2", "__AVR_ATmega128RFR2__"}, - {"atmega1284rfr2", "__AVR_ATmega1284RFR2__"}, - {"at90can128", "__AVR_AT90CAN128__"}, - {"at90usb1286", "__AVR_AT90USB1286__"}, - {"at90usb1287", "__AVR_AT90USB1287__"}, - {"atmega2560", "__AVR_ATmega2560__"}, - {"atmega2561", "__AVR_ATmega2561__"}, - {"atmega256rfr2", "__AVR_ATmega256RFR2__"}, - {"atmega2564rfr2", "__AVR_ATmega2564RFR2__"}, - {"atxmega16a4", "__AVR_ATxmega16A4__"}, - {"atxmega16a4u", "__AVR_ATxmega16A4U__"}, - {"atxmega16c4", "__AVR_ATxmega16C4__"}, - {"atxmega16d4", "__AVR_ATxmega16D4__"}, - {"atxmega32a4", "__AVR_ATxmega32A4__"}, - {"atxmega32a4u", "__AVR_ATxmega32A4U__"}, - {"atxmega32c4", "__AVR_ATxmega32C4__"}, - {"atxmega32d4", "__AVR_ATxmega32D4__"}, - {"atxmega32e5", "__AVR_ATxmega32E5__"}, - {"atxmega16e5", "__AVR_ATxmega16E5__"}, - {"atxmega8e5", "__AVR_ATxmega8E5__"}, - {"atxmega32x1", "__AVR_ATxmega32X1__"}, - {"atxmega64a3", "__AVR_ATxmega64A3__"}, - {"atxmega64a3u", "__AVR_ATxmega64A3U__"}, - {"atxmega64a4u", "__AVR_ATxmega64A4U__"}, - {"atxmega64b1", "__AVR_ATxmega64B1__"}, - {"atxmega64b3", "__AVR_ATxmega64B3__"}, - {"atxmega64c3", "__AVR_ATxmega64C3__"}, - {"atxmega64d3", "__AVR_ATxmega64D3__"}, - {"atxmega64d4", "__AVR_ATxmega64D4__"}, - {"atxmega64a1", "__AVR_ATxmega64A1__"}, - {"atxmega64a1u", "__AVR_ATxmega64A1U__"}, - {"atxmega128a3", "__AVR_ATxmega128A3__"}, - {"atxmega128a3u", "__AVR_ATxmega128A3U__"}, - {"atxmega128b1", "__AVR_ATxmega128B1__"}, - {"atxmega128b3", "__AVR_ATxmega128B3__"}, - {"atxmega128c3", "__AVR_ATxmega128C3__"}, - {"atxmega128d3", "__AVR_ATxmega128D3__"}, - {"atxmega128d4", "__AVR_ATxmega128D4__"}, - {"atxmega192a3", "__AVR_ATxmega192A3__"}, - {"atxmega192a3u", "__AVR_ATxmega192A3U__"}, - {"atxmega192c3", "__AVR_ATxmega192C3__"}, - {"atxmega192d3", "__AVR_ATxmega192D3__"}, - {"atxmega256a3", "__AVR_ATxmega256A3__"}, - {"atxmega256a3u", "__AVR_ATxmega256A3U__"}, - {"atxmega256a3b", "__AVR_ATxmega256A3B__"}, - {"atxmega256a3bu", "__AVR_ATxmega256A3BU__"}, - {"atxmega256c3", "__AVR_ATxmega256C3__"}, - {"atxmega256d3", "__AVR_ATxmega256D3__"}, - {"atxmega384c3", "__AVR_ATxmega384C3__"}, - {"atxmega384d3", "__AVR_ATxmega384D3__"}, - {"atxmega128a1", "__AVR_ATxmega128A1__"}, - {"atxmega128a1u", "__AVR_ATxmega128A1U__"}, - {"atxmega128a4u", "__AVR_ATxmega128A4U__"}, - {"attiny4", "__AVR_ATtiny4__"}, - {"attiny5", "__AVR_ATtiny5__"}, - {"attiny9", "__AVR_ATtiny9__"}, - {"attiny10", "__AVR_ATtiny10__"}, - {"attiny20", "__AVR_ATtiny20__"}, - {"attiny40", "__AVR_ATtiny40__"}, - {"attiny102", "__AVR_ATtiny102__"}, - {"attiny104", "__AVR_ATtiny104__"}, - {"attiny202", "__AVR_ATtiny202__"}, - {"attiny402", "__AVR_ATtiny402__"}, - {"attiny204", "__AVR_ATtiny204__"}, - {"attiny404", "__AVR_ATtiny404__"}, - {"attiny804", "__AVR_ATtiny804__"}, - {"attiny1604", "__AVR_ATtiny1604__"}, - {"attiny406", "__AVR_ATtiny406__"}, - {"attiny806", "__AVR_ATtiny806__"}, - {"attiny1606", "__AVR_ATtiny1606__"}, - {"attiny807", "__AVR_ATtiny807__"}, - {"attiny1607", "__AVR_ATtiny1607__"}, - {"attiny212", "__AVR_ATtiny212__"}, - {"attiny412", "__AVR_ATtiny412__"}, - {"attiny214", "__AVR_ATtiny214__"}, - {"attiny414", "__AVR_ATtiny414__"}, - {"attiny814", "__AVR_ATtiny814__"}, - {"attiny1614", "__AVR_ATtiny1614__"}, - {"attiny416", "__AVR_ATtiny416__"}, - {"attiny816", "__AVR_ATtiny816__"}, - {"attiny1616", "__AVR_ATtiny1616__"}, - {"attiny3216", "__AVR_ATtiny3216__"}, - {"attiny417", "__AVR_ATtiny417__"}, - {"attiny817", "__AVR_ATtiny817__"}, - {"attiny1617", "__AVR_ATtiny1617__"}, - {"attiny3217", "__AVR_ATtiny3217__"}, + {"at90s1200", "__AVR_AT90S1200__", 0}, + {"attiny11", "__AVR_ATtiny11__", 0}, + {"attiny12", "__AVR_ATtiny12__", 0}, + {"attiny15", "__AVR_ATtiny15__", 0}, + {"attiny28", "__AVR_ATtiny28__", 0}, + {"at90s2313", "__AVR_AT90S2313__", 1}, + {"at90s2323", "__AVR_AT90S2323__", 1}, + {"at90s2333", "__AVR_AT90S2333__", 1}, + {"at90s2343", "__AVR_AT90S2343__", 1}, + {"attiny22", "__AVR_ATtiny22__", 1}, + {"attiny26", "__AVR_ATtiny26__", 1}, + {"at86rf401", "__AVR_AT86RF401__", 1}, + {"at90s4414", "__AVR_AT90S4414__", 1}, + {"at90s4433", "__AVR_AT90S4433__", 1}, + {"at90s4434", "__AVR_AT90S4434__", 1}, + {"at90s8515", "__AVR_AT90S8515__", 1}, + {"at90c8534", "__AVR_AT90c8534__", 1}, + {"at90s8535", "__AVR_AT90S8535__", 1}, + {"ata5272", "__AVR_ATA5272__", 1}, + {"attiny13", "__AVR_ATtiny13__", 1}, + {"attiny13a", "__AVR_ATtiny13A__", 1}, + {"attiny2313", "__AVR_ATtiny2313__", 1}, + {"attiny2313a", "__AVR_ATtiny2313A__", 1}, + {"attiny24", "__AVR_ATtiny24__", 1}, + {"attiny24a", "__AVR_ATtiny24A__", 1}, + {"attiny4313", "__AVR_ATtiny4313__", 1}, + {"attiny44", "__AVR_ATtiny44__", 1}, + {"attiny44a", "__AVR_ATtiny44A__", 1}, + {"attiny84", "__AVR_ATtiny84__", 1}, + {"attiny84a", "__AVR_ATtiny84A__", 1}, + {"attiny25", "__AVR_ATtiny25__", 1}, + {"attiny45", "__AVR_ATtiny45__", 1}, + {"attiny85", "__AVR_ATtiny85__", 1}, + {"attiny261", "__AVR_ATtiny261__", 1}, + {"attiny261a", "__AVR_ATtiny261A__", 1}, + {"attiny441", "__AVR_ATtiny441__", 1}, + {"attiny461", "__AVR_ATtiny461__", 1}, + {"attiny461a", "__AVR_ATtiny461A__", 1}, + {"attiny841", "__AVR_ATtiny841__", 1}, + {"attiny861", "__AVR_ATtiny861__", 1}, + {"attiny861a", "__AVR_ATtiny861A__", 1}, + {"attiny87", "__AVR_ATtiny87__", 1}, + {"attiny43u", "__AVR_ATtiny43U__", 1}, + {"attiny48", "__AVR_ATtiny48__", 1}, + {"attiny88", "__AVR_ATtiny88__", 1}, + {"attiny828", "__AVR_ATtiny828__", 1}, + {"at43usb355", "__AVR_AT43USB355__", 1}, + {"at76c711", "__AVR_AT76C711__", 1}, + {"atmega103", "__AVR_ATmega103__", 1}, + {"at43usb320", "__AVR_AT43USB320__", 1}, + {"attiny167", "__AVR_ATtiny167__", 1}, + {"at90usb82", "__AVR_AT90USB82__", 1}, + {"at90usb162", "__AVR_AT90USB162__", 1}, + {"ata5505", "__AVR_ATA5505__", 1}, + {"atmega8u2", "__AVR_ATmega8U2__", 1}, + {"atmega16u2", "__AVR_ATmega16U2__", 1}, + {"atmega32u2", "__AVR_ATmega32U2__", 1}, + {"attiny1634", "__AVR_ATtiny1634__", 1}, + {"atmega8", "__AVR_ATmega8__", 1}, + {"ata6289", "__AVR_ATA6289__", 1}, + {"atmega8a", "__AVR_ATmega8A__", 1}, + {"ata6285", "__AVR_ATA6285__", 1}, + {"ata6286", "__AVR_ATA6286__", 1}, + {"atmega48", "__AVR_ATmega48__", 1}, + {"atmega48a", "__AVR_ATmega48A__", 1}, + {"atmega48pa", "__AVR_ATmega48PA__", 1}, + {"atmega48pb", "__AVR_ATmega48PB__", 1}, + {"atmega48p", "__AVR_ATmega48P__", 1}, + {"atmega88", "__AVR_ATmega88__", 1}, + {"atmega88a", "__AVR_ATmega88A__", 1}, + {"atmega88p", "__AVR_ATmega88P__", 1}, + {"atmega88pa", "__AVR_ATmega88PA__", 1}, + {"atmega88pb", "__AVR_ATmega88PB__", 1}, + {"atmega8515", "__AVR_ATmega8515__", 1}, + {"atmega8535", "__AVR_ATmega8535__", 1}, + {"atmega8hva", "__AVR_ATmega8HVA__", 1}, + {"at90pwm1", "__AVR_AT90PWM1__", 1}, + {"at90pwm2", "__AVR_AT90PWM2__", 1}, + {"at90pwm2b", "__AVR_AT90PWM2B__", 1}, + {"at90pwm3", "__AVR_AT90PWM3__", 1}, + {"at90pwm3b", "__AVR_AT90PWM3B__", 1}, + {"at90pwm81", "__AVR_AT90PWM81__", 1}, + {"ata5790", "__AVR_ATA5790__", 1}, + {"ata5795", "__AVR_ATA5795__", 1}, + {"atmega16", "__AVR_ATmega16__", 1}, + {"atmega16a", "__AVR_ATmega16A__", 1}, + {"atmega161", "__AVR_ATmega161__", 1}, + {"atmega162", "__AVR_ATmega162__", 1}, + {"atmega163", "__AVR_ATmega163__", 1}, + {"atmega164a", "__AVR_ATmega164A__", 1}, + {"atmega164p", "__AVR_ATmega164P__", 1}, + {"atmega164pa", "__AVR_ATmega164PA__", 1}, + {"atmega165", "__AVR_ATmega165__", 1}, + {"atmega165a", "__AVR_ATmega165A__", 1}, + {"atmega165p", "__AVR_ATmega165P__", 1}, + {"atmega165pa", "__AVR_ATmega165PA__", 1}, + {"atmega168", "__AVR_ATmega168__", 1}, + {"atmega168a", "__AVR_ATmega168A__", 1}, + {"atmega168p", "__AVR_ATmega168P__", 1}, + {"atmega168pa", "__AVR_ATmega168PA__", 1}, + {"atmega168pb", "__AVR_ATmega168PB__", 1}, + {"atmega169", "__AVR_ATmega169__", 1}, + {"atmega169a", "__AVR_ATmega169A__", 1}, + {"atmega169p", "__AVR_ATmega169P__", 1}, + {"atmega169pa", "__AVR_ATmega169PA__", 1}, + {"atmega32", "__AVR_ATmega32__", 1}, + {"atmega32a", "__AVR_ATmega32A__", 1}, + {"atmega323", "__AVR_ATmega323__", 1}, + {"atmega324a", "__AVR_ATmega324A__", 1}, + {"atmega324p", "__AVR_ATmega324P__", 1}, + {"atmega324pa", "__AVR_ATmega324PA__", 1}, + {"atmega324pb", "__AVR_ATmega324PB__", 1}, + {"atmega325", "__AVR_ATmega325__", 1}, + {"atmega325a", "__AVR_ATmega325A__", 1}, + {"atmega325p", "__AVR_ATmega325P__", 1}, + {"atmega325pa", "__AVR_ATmega325PA__", 1}, + {"atmega3250", "__AVR_ATmega3250__", 1}, + {"atmega3250a", "__AVR_ATmega3250A__", 1}, + {"atmega3250p", "__AVR_ATmega3250P__", 1}, + {"atmega3250pa", "__AVR_ATmega3250PA__", 1}, + {"atmega328", "__AVR_ATmega328__", 1}, + {"atmega328p", "__AVR_ATmega328P__", 1}, + {"atmega328pb", "__AVR_ATmega328PB__", 1}, + {"atmega329", "__AVR_ATmega329__", 1}, + {"atmega329a", "__AVR_ATmega329A__", 1}, + {"atmega329p", "__AVR_ATmega329P__", 1}, + {"atmega329pa", "__AVR_ATmega329PA__", 1}, + {"atmega3290", "__AVR_ATmega3290__", 1}, + {"atmega3290a", "__AVR_ATmega3290A__", 1}, + {"atmega3290p", "__AVR_ATmega3290P__", 1}, + {"atmega3290pa", "__AVR_ATmega3290PA__", 1}, + {"atmega406", "__AVR_ATmega406__", 1}, + {"atmega64", "__AVR_ATmega64__", 1}, + {"atmega64a", "__AVR_ATmega64A__", 1}, + {"atmega640", "__AVR_ATmega640__", 1}, + {"atmega644", "__AVR_ATmega644__", 1}, + {"atmega644a", "__AVR_ATmega644A__", 1}, + {"atmega644p", "__AVR_ATmega644P__", 1}, + {"atmega644pa", "__AVR_ATmega644PA__", 1}, + {"atmega645", "__AVR_ATmega645__", 1}, + {"atmega645a", "__AVR_ATmega645A__", 1}, + {"atmega645p", "__AVR_ATmega645P__", 1}, + {"atmega649", "__AVR_ATmega649__", 1}, + {"atmega649a", "__AVR_ATmega649A__", 1}, + {"atmega649p", "__AVR_ATmega649P__", 1}, + {"atmega6450", "__AVR_ATmega6450__", 1}, + {"atmega6450a", "__AVR_ATmega6450A__", 1}, + {"atmega6450p", "__AVR_ATmega6450P__", 1}, + {"atmega6490", "__AVR_ATmega6490__", 1}, + {"atmega6490a", "__AVR_ATmega6490A__", 1}, + {"atmega6490p", "__AVR_ATmega6490P__", 1}, + {"atmega64rfr2", "__AVR_ATmega64RFR2__", 1}, + {"atmega644rfr2", "__AVR_ATmega644RFR2__", 1}, + {"atmega16hva", "__AVR_ATmega16HVA__", 1}, + {"atmega16hva2", "__AVR_ATmega16HVA2__", 1}, + {"atmega16hvb", "__AVR_ATmega16HVB__", 1}, + {"atmega16hvbrevb", "__AVR_ATmega16HVBREVB__", 1}, + {"atmega32hvb", "__AVR_ATmega32HVB__", 1}, + {"atmega32hvbrevb", "__AVR_ATmega32HVBREVB__", 1}, + {"atmega64hve", "__AVR_ATmega64HVE__", 1}, + {"at90can32", "__AVR_AT90CAN32__", 1}, + {"at90can64", "__AVR_AT90CAN64__", 1}, + {"at90pwm161", "__AVR_AT90PWM161__", 1}, + {"at90pwm216", "__AVR_AT90PWM216__", 1}, + {"at90pwm316", "__AVR_AT90PWM316__", 1}, + {"atmega32c1", "__AVR_ATmega32C1__", 1}, + {"atmega64c1", "__AVR_ATmega64C1__", 1}, + {"atmega16m1", "__AVR_ATmega16M1__", 1}, + {"atmega32m1", "__AVR_ATmega32M1__", 1}, + {"atmega64m1", "__AVR_ATmega64M1__", 1}, + {"atmega16u4", "__AVR_ATmega16U4__", 1}, + {"atmega32u4", "__AVR_ATmega32U4__", 1}, + {"atmega32u6", "__AVR_ATmega32U6__", 1}, + {"at90usb646", "__AVR_AT90USB646__", 1}, + {"at90usb647", "__AVR_AT90USB647__", 1}, + {"at90scr100", "__AVR_AT90SCR100__", 1}, + {"at94k", "__AVR_AT94K__", 1}, + {"m3000", "__AVR_AT000__", 1}, + {"atmega128", "__AVR_ATmega128__", 2}, + {"atmega128a", "__AVR_ATmega128A__", 2}, + {"atmega1280", "__AVR_ATmega1280__", 2}, + {"atmega1281", "__AVR_ATmega1281__", 2}, + {"atmega1284", "__AVR_ATmega1284__", 2}, + {"atmega1284p", "__AVR_ATmega1284P__", 2}, + {"atmega128rfa1", "__AVR_ATmega128RFA1__", 2}, + {"atmega128rfr2", "__AVR_ATmega128RFR2__", 2}, + {"atmega1284rfr2", "__AVR_ATmega1284RFR2__", 2}, + {"at90can128", "__AVR_AT90CAN128__", 2}, + {"at90usb1286", "__AVR_AT90USB1286__", 2}, + {"at90usb1287", "__AVR_AT90USB1287__", 2}, + {"atmega2560", "__AVR_ATmega2560__", 4}, + {"atmega2561", "__AVR_ATmega2561__", 4}, + {"atmega256rfr2", "__AVR_ATmega256RFR2__", 4}, + {"atmega2564rfr2", "__AVR_ATmega2564RFR2__", 4}, + {"atxmega16a4", "__AVR_ATxmega16A4__", 1}, + {"atxmega16a4u", "__AVR_ATxmega16A4U__", 1}, + {"atxmega16c4", "__AVR_ATxmega16C4__", 1}, + {"atxmega16d4", "__AVR_ATxmega16D4__", 1}, + {"atxmega32a4", "__AVR_ATxmega32A4__", 1}, + {"atxmega32a4u", "__AVR_ATxmega32A4U__", 1}, + {"atxmega32c4", "__AVR_ATxmega32C4__", 1}, + {"atxmega32d4", "__AVR_ATxmega32D4__", 1}, + {"atxmega32e5", "__AVR_ATxmega32E5__", 1}, + {"atxmega16e5", "__AVR_ATxmega16E5__", 1}, + {"atxmega8e5", "__AVR_ATxmega8E5__", 1}, + {"atxmega32x1", "__AVR_ATxmega32X1__", 1}, + {"atxmega64a3", "__AVR_ATxmega64A3__", 1}, + {"atxmega64a3u", "__AVR_ATxmega64A3U__", 1}, + {"atxmega64a4u", "__AVR_ATxmega64A4U__", 1}, + {"atxmega64b1", "__AVR_ATxmega64B1__", 1}, + {"atxmega64b3", "__AVR_ATxmega64B3__", 1}, + {"atxmega64c3", "__AVR_ATxmega64C3__", 1}, + {"atxmega64d3", "__AVR_ATxmega64D3__", 1}, + {"atxmega64d4", "__AVR_ATxmega64D4__", 1}, + {"atxmega64a1", "__AVR_ATxmega64A1__", 1}, + {"atxmega64a1u", "__AVR_ATxmega64A1U__", 1}, + {"atxmega128a3", "__AVR_ATxmega128A3__", 2}, + {"atxmega128a3u", "__AVR_ATxmega128A3U__", 2}, + {"atxmega128b1", "__AVR_ATxmega128B1__", 2}, + {"atxmega128b3", "__AVR_ATxmega128B3__", 2}, + {"atxmega128c3", "__AVR_ATxmega128C3__", 2}, + {"atxmega128d3", "__AVR_ATxmega128D3__", 2}, + {"atxmega128d4", "__AVR_ATxmega128D4__", 2}, + {"atxmega192a3", "__AVR_ATxmega192A3__", 3}, + {"atxmega192a3u", "__AVR_ATxmega192A3U__", 3}, + {"atxmega192c3", "__AVR_ATxmega192C3__", 3}, + {"atxmega192d3", "__AVR_ATxmega192D3__", 3}, + {"atxmega256a3", "__AVR_ATxmega256A3__", 4}, + {"atxmega256a3u", "__AVR_ATxmega256A3U__", 4}, + {"atxmega256a3b", "__AVR_ATxmega256A3B__", 4}, + {"atxmega256a3bu", "__AVR_ATxmega256A3BU__", 4}, + {"atxmega256c3", "__AVR_ATxmega256C3__", 4}, + {"atxmega256d3", "__AVR_ATxmega256D3__", 4}, + {"atxmega384c3", "__AVR_ATxmega384C3__", 6}, + {"atxmega384d3", "__AVR_ATxmega384D3__", 6}, + {"atxmega128a1", "__AVR_ATxmega128A1__", 2}, + {"atxmega128a1u", "__AVR_ATxmega128A1U__", 2}, + {"atxmega128a4u", "__AVR_ATxmega128A4U__", 2}, + {"attiny4", "__AVR_ATtiny4__", 0}, + {"attiny5", "__AVR_ATtiny5__", 0}, + {"attiny9", "__AVR_ATtiny9__", 0}, + {"attiny10", "__AVR_ATtiny10__", 0}, + {"attiny20", "__AVR_ATtiny20__", 0}, + {"attiny40", "__AVR_ATtiny40__", 0}, + {"attiny102", "__AVR_ATtiny102__", 0}, + {"attiny104", "__AVR_ATtiny104__", 0}, + {"attiny202", "__AVR_ATtiny202__", 1}, + {"attiny402", "__AVR_ATtiny402__", 1}, + {"attiny204", "__AVR_ATtiny204__", 1}, + {"attiny404", "__AVR_ATtiny404__", 1}, + {"attiny804", "__AVR_ATtiny804__", 1}, + {"attiny1604", "__AVR_ATtiny1604__", 1}, + {"attiny406", "__AVR_ATtiny406__", 1}, + {"attiny806", "__AVR_ATtiny806__", 1}, + {"attiny1606", "__AVR_ATtiny1606__", 1}, + {"attiny807", "__AVR_ATtiny807__", 1}, + {"attiny1607", "__AVR_ATtiny1607__", 1}, + {"attiny212", "__AVR_ATtiny212__", 1}, + {"attiny412", "__AVR_ATtiny412__", 1}, + {"attiny214", "__AVR_ATtiny214__", 1}, + {"attiny414", "__AVR_ATtiny414__", 1}, + {"attiny814", "__AVR_ATtiny814__", 1}, + {"attiny1614", "__AVR_ATtiny1614__", 1}, + {"attiny416", "__AVR_ATtiny416__", 1}, + {"attiny816", "__AVR_ATtiny816__", 1}, + {"attiny1616", "__AVR_ATtiny1616__", 1}, + {"attiny3216", "__AVR_ATtiny3216__", 1}, + {"attiny417", "__AVR_ATtiny417__", 1}, + {"attiny817", "__AVR_ATtiny817__", 1}, + {"attiny1617", "__AVR_ATtiny1617__", 1}, + {"attiny3217", "__AVR_ATtiny3217__", 1}, }; } // namespace targets @@ -330,13 +331,25 @@ void AVRTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__AVR"); Builder.defineMacro("__AVR__"); Builder.defineMacro("__ELF__"); - Builder.defineMacro("__flash", "__attribute__((address_space(1)))"); if (!this->CPU.empty()) { auto It = llvm::find_if( AVRMcus, [&](const MCUInfo &Info) { return Info.Name == this->CPU; }); - if (It != std::end(AVRMcus)) + if (It != std::end(AVRMcus)) { Builder.defineMacro(It->DefineName); + if (It->NumFlashBanks >= 1) + Builder.defineMacro("__flash", "__attribute__((address_space(1)))"); + if (It->NumFlashBanks >= 2) + Builder.defineMacro("__flash1", "__attribute__((address_space(2)))"); + if (It->NumFlashBanks >= 3) + Builder.defineMacro("__flash2", "__attribute__((address_space(3)))"); + if (It->NumFlashBanks >= 4) + Builder.defineMacro("__flash3", "__attribute__((address_space(4)))"); + if (It->NumFlashBanks >= 5) + Builder.defineMacro("__flash4", "__attribute__((address_space(5)))"); + if (It->NumFlashBanks >= 6) + Builder.defineMacro("__flash5", "__attribute__((address_space(6)))"); + } } } diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h index 89a80ca6a39a..a281e2c2cd74 100644 --- a/clang/lib/Basic/Targets/AVR.h +++ b/clang/lib/Basic/Targets/AVR.h @@ -55,6 +55,7 @@ public: Int16Type = SignedInt; Char32Type = UnsignedLong; SigAtomicType = SignedChar; + ProgramAddrSpace = 1; resetDataLayout("e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8"); } diff --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp index c0cd8fa90ed6..ada5b97ed66d 100644 --- a/clang/lib/Basic/Targets/M68k.cpp +++ b/clang/lib/Basic/Targets/M68k.cpp @@ -29,7 +29,7 @@ M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { - std::string Layout = ""; + std::string Layout; // M68k is Big Endian Layout += "E"; diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 7f7b44b658eb..1eb0317af60b 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -561,9 +561,9 @@ bool PPCTargetInfo::initFeatureMap( if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) return false; - if (!(ArchDefs & ArchDefinePwr9) && (ArchDefs & ArchDefinePpcgr) && + if (!(ArchDefs & ArchDefinePwr7) && (ArchDefs & ArchDefinePpcgr) && llvm::is_contained(FeaturesVec, "+float128")) { - // We have __float128 on PPC but not power 9 and above. + // We have __float128 on PPC but not pre-VSX targets. Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" << CPU; return false; } @@ -734,23 +734,28 @@ ArrayRef<const char *> PPCTargetInfo::getGCCRegNames() const { const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { // While some of these aliases do map to different registers // they still share the same register name. - {{"0"}, "r0"}, {{"1"}, "r1"}, {{"2"}, "r2"}, {{"3"}, "r3"}, - {{"4"}, "r4"}, {{"5"}, "r5"}, {{"6"}, "r6"}, {{"7"}, "r7"}, - {{"8"}, "r8"}, {{"9"}, "r9"}, {{"10"}, "r10"}, {{"11"}, "r11"}, - {{"12"}, "r12"}, {{"13"}, "r13"}, {{"14"}, "r14"}, {{"15"}, "r15"}, - {{"16"}, "r16"}, {{"17"}, "r17"}, {{"18"}, "r18"}, {{"19"}, "r19"}, - {{"20"}, "r20"}, {{"21"}, "r21"}, {{"22"}, "r22"}, {{"23"}, "r23"}, - {{"24"}, "r24"}, {{"25"}, "r25"}, {{"26"}, "r26"}, {{"27"}, "r27"}, - {{"28"}, "r28"}, {{"29"}, "r29"}, {{"30"}, "r30"}, {{"31"}, "r31"}, - {{"fr0"}, "f0"}, {{"fr1"}, "f1"}, {{"fr2"}, "f2"}, {{"fr3"}, "f3"}, - {{"fr4"}, "f4"}, {{"fr5"}, "f5"}, {{"fr6"}, "f6"}, {{"fr7"}, "f7"}, - {{"fr8"}, "f8"}, {{"fr9"}, "f9"}, {{"fr10"}, "f10"}, {{"fr11"}, "f11"}, - {{"fr12"}, "f12"}, {{"fr13"}, "f13"}, {{"fr14"}, "f14"}, {{"fr15"}, "f15"}, - {{"fr16"}, "f16"}, {{"fr17"}, "f17"}, {{"fr18"}, "f18"}, {{"fr19"}, "f19"}, - {{"fr20"}, "f20"}, {{"fr21"}, "f21"}, {{"fr22"}, "f22"}, {{"fr23"}, "f23"}, - {{"fr24"}, "f24"}, {{"fr25"}, "f25"}, {{"fr26"}, "f26"}, {{"fr27"}, "f27"}, - {{"fr28"}, "f28"}, {{"fr29"}, "f29"}, {{"fr30"}, "f30"}, {{"fr31"}, "f31"}, - {{"cc"}, "cr0"}, + {{"0"}, "r0"}, {{"1", "sp"}, "r1"}, {{"2"}, "r2"}, + {{"3"}, "r3"}, {{"4"}, "r4"}, {{"5"}, "r5"}, + {{"6"}, "r6"}, {{"7"}, "r7"}, {{"8"}, "r8"}, + {{"9"}, "r9"}, {{"10"}, "r10"}, {{"11"}, "r11"}, + {{"12"}, "r12"}, {{"13"}, "r13"}, {{"14"}, "r14"}, + {{"15"}, "r15"}, {{"16"}, "r16"}, {{"17"}, "r17"}, + {{"18"}, "r18"}, {{"19"}, "r19"}, {{"20"}, "r20"}, + {{"21"}, "r21"}, {{"22"}, "r22"}, {{"23"}, "r23"}, + {{"24"}, "r24"}, {{"25"}, "r25"}, {{"26"}, "r26"}, + {{"27"}, "r27"}, {{"28"}, "r28"}, {{"29"}, "r29"}, + {{"30"}, "r30"}, {{"31"}, "r31"}, {{"fr0"}, "f0"}, + {{"fr1"}, "f1"}, {{"fr2"}, "f2"}, {{"fr3"}, "f3"}, + {{"fr4"}, "f4"}, {{"fr5"}, "f5"}, {{"fr6"}, "f6"}, + {{"fr7"}, "f7"}, {{"fr8"}, "f8"}, {{"fr9"}, "f9"}, + {{"fr10"}, "f10"}, {{"fr11"}, "f11"}, {{"fr12"}, "f12"}, + {{"fr13"}, "f13"}, {{"fr14"}, "f14"}, {{"fr15"}, "f15"}, + {{"fr16"}, "f16"}, {{"fr17"}, "f17"}, {{"fr18"}, "f18"}, + {{"fr19"}, "f19"}, {{"fr20"}, "f20"}, {{"fr21"}, "f21"}, + {{"fr22"}, "f22"}, {{"fr23"}, "f23"}, {{"fr24"}, "f24"}, + {{"fr25"}, "f25"}, {{"fr26"}, "f26"}, {{"fr27"}, "f27"}, + {{"fr28"}, "f28"}, {{"fr29"}, "f29"}, {{"fr30"}, "f30"}, + {{"fr31"}, "f31"}, {{"cc"}, "cr0"}, }; ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const { diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 60701072ac4b..ac52eb219f54 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -414,7 +414,7 @@ public: LongWidth = LongAlign = PointerWidth = PointerAlign = 64; IntMaxType = SignedLong; Int64Type = SignedLong; - std::string DataLayout = ""; + std::string DataLayout; if (Triple.isOSAIX()) { // TODO: Set appropriate ABI for AIX platform. diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 770d37a1c1be..0680cad5b07c 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -125,6 +125,9 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32"); StringRef CodeModel = getTargetOpts().CodeModel; unsigned FLen = ISAInfo->getFLen(); + unsigned MinVLen = ISAInfo->getMinVLen(); + unsigned MaxELen = ISAInfo->getMaxELen(); + unsigned MaxELenFp = ISAInfo->getMaxELenFp(); if (CodeModel == "default") CodeModel = "small"; @@ -176,10 +179,16 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__riscv_fsqrt"); } + if (MinVLen) { + Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen)); + Builder.defineMacro("__riscv_v_elen", Twine(MaxELen)); + Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp)); + } + if (ISAInfo->hasExtension("c")) Builder.defineMacro("__riscv_compressed"); - if (ISAInfo->hasExtension("v")) + if (ISAInfo->hasExtension("zve32x") || ISAInfo->hasExtension("v")) Builder.defineMacro("__riscv_vector"); } @@ -205,10 +214,26 @@ bool RISCVTargetInfo::initFeatureMap( llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector<std::string> &FeaturesVec) const { - if (getTriple().getArch() == llvm::Triple::riscv64) + unsigned XLen = 32; + + if (getTriple().getArch() == llvm::Triple::riscv64) { Features["64bit"] = true; + XLen = 64; + } + + auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec); + if (!ParseResult) { + std::string Buffer; + llvm::raw_string_ostream OutputErrMsg(Buffer); + handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { + OutputErrMsg << ErrMsg.getMessage(); + }); + Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); + return false; + } - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + return TargetInfo::initFeatureMap(Features, Diags, CPU, + (*ParseResult)->toFeatureVector()); } /// Return true if has this feature, need to sync with handleTargetFeatures. diff --git a/clang/lib/Basic/Targets/Sparc.cpp b/clang/lib/Basic/Targets/Sparc.cpp index 5eeb77406c34..932102434801 100644 --- a/clang/lib/Basic/Targets/Sparc.cpp +++ b/clang/lib/Basic/Targets/Sparc.cpp @@ -156,8 +156,6 @@ void SparcV8TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__sparcv8__"); break; case CG_V9: - Builder.defineMacro("__sparcv9"); - Builder.defineMacro("__sparcv9__"); Builder.defineMacro("__sparc_v9__"); break; } diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index c952b8c9a336..d1b66432e38b 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -533,11 +533,12 @@ public: DoubleAlign = LongLongAlign = 64; bool IsWinCOFF = getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); - resetDataLayout(IsWinCOFF ? "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:" - "64-i64:64-f80:32-n8:16:32-a:0:32-S32" - : "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:" - "64-i64:64-f80:32-n8:16:32-a:0:32-S32", - IsWinCOFF ? "_" : ""); + bool IsMSVC = getTriple().isWindowsMSVCEnvironment(); + std::string Layout = IsWinCOFF ? "e-m:x" : "e-m:e"; + Layout += "-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-"; + Layout += IsMSVC ? "f80:128" : "f80:32"; + Layout += "-n8:16:32-a:0:32-S32"; + resetDataLayout(Layout, IsWinCOFF ? "_" : ""); } }; diff --git a/clang/lib/CodeGen/Address.h b/clang/lib/CodeGen/Address.h index 37c20291c0e8..3ac0f4f0d7e5 100644 --- a/clang/lib/CodeGen/Address.h +++ b/clang/lib/CodeGen/Address.h @@ -14,30 +14,77 @@ #ifndef LLVM_CLANG_LIB_CODEGEN_ADDRESS_H #define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H -#include "llvm/IR/Constants.h" #include "clang/AST/CharUnits.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/IR/Constants.h" +#include "llvm/Support/MathExtras.h" namespace clang { namespace CodeGen { -/// An aligned address. -class Address { +// We try to save some space by using 6 bits over two PointerIntPairs to store +// the alignment. However, some arches don't support 3 bits in a PointerIntPair +// so we fallback to storing the alignment separately. +template <typename T, bool = alignof(llvm::Value *) >= 8> class AddressImpl {}; + +template <typename T> class AddressImpl<T, false> { llvm::Value *Pointer; llvm::Type *ElementType; CharUnits Alignment; +public: + AddressImpl(llvm::Value *Pointer, llvm::Type *ElementType, + CharUnits Alignment) + : Pointer(Pointer), ElementType(ElementType), Alignment(Alignment) {} + llvm::Value *getPointer() const { return Pointer; } + llvm::Type *getElementType() const { return ElementType; } + CharUnits getAlignment() const { return Alignment; } +}; + +template <typename T> class AddressImpl<T, true> { + // Int portion stores upper 3 bits of the log of the alignment. + llvm::PointerIntPair<llvm::Value *, 3, unsigned> Pointer; + // Int portion stores lower 3 bits of the log of the alignment. + llvm::PointerIntPair<llvm::Type *, 3, unsigned> ElementType; + +public: + AddressImpl(llvm::Value *Pointer, llvm::Type *ElementType, + CharUnits Alignment) + : Pointer(Pointer), ElementType(ElementType) { + if (Alignment.isZero()) + return; + // Currently the max supported alignment is much less than 1 << 63 and is + // guaranteed to be a power of 2, so we can store the log of the alignment + // into 6 bits. + assert(Alignment.isPowerOfTwo() && "Alignment cannot be zero"); + auto AlignLog = llvm::Log2_64(Alignment.getQuantity()); + assert(AlignLog < (1 << 6) && "cannot fit alignment into 6 bits"); + this->Pointer.setInt(AlignLog >> 3); + this->ElementType.setInt(AlignLog & 7); + } + llvm::Value *getPointer() const { return Pointer.getPointer(); } + llvm::Type *getElementType() const { return ElementType.getPointer(); } + CharUnits getAlignment() const { + unsigned AlignLog = (Pointer.getInt() << 3) | ElementType.getInt(); + return CharUnits::fromQuantity(CharUnits::QuantityType(1) << AlignLog); + } +}; + +/// An aligned address. +class Address { + AddressImpl<void> A; + protected: - Address(std::nullptr_t) : Pointer(nullptr), ElementType(nullptr) {} + Address(std::nullptr_t) : A(nullptr, nullptr, CharUnits::Zero()) {} public: - Address(llvm::Value *pointer, llvm::Type *elementType, CharUnits alignment) - : Pointer(pointer), ElementType(elementType), Alignment(alignment) { - assert(pointer != nullptr && "Pointer cannot be null"); - assert(elementType != nullptr && "Element type cannot be null"); - assert(llvm::cast<llvm::PointerType>(pointer->getType()) - ->isOpaqueOrPointeeTypeMatches(elementType) && + Address(llvm::Value *Pointer, llvm::Type *ElementType, CharUnits Alignment) + : A(Pointer, ElementType, Alignment) { + assert(Pointer != nullptr && "Pointer cannot be null"); + assert(ElementType != nullptr && "Element type cannot be null"); + assert(llvm::cast<llvm::PointerType>(Pointer->getType()) + ->isOpaqueOrPointeeTypeMatches(ElementType) && "Incorrect pointer element type"); - assert(!alignment.isZero() && "Alignment cannot be zero"); } // Deprecated: Use constructor with explicit element type instead. @@ -46,11 +93,11 @@ public: Alignment) {} static Address invalid() { return Address(nullptr); } - bool isValid() const { return Pointer != nullptr; } + bool isValid() const { return A.getPointer() != nullptr; } llvm::Value *getPointer() const { assert(isValid()); - return Pointer; + return A.getPointer(); } /// Return the type of the pointer value. @@ -61,7 +108,7 @@ public: /// Return the type of the values stored in this address. llvm::Type *getElementType() const { assert(isValid()); - return ElementType; + return A.getElementType(); } /// Return the address space that this address resides in. @@ -77,19 +124,19 @@ public: /// Return the alignment of this pointer. CharUnits getAlignment() const { assert(isValid()); - return Alignment; + return A.getAlignment(); } /// Return address with different pointer, but same element type and /// alignment. Address withPointer(llvm::Value *NewPointer) const { - return Address(NewPointer, ElementType, Alignment); + return Address(NewPointer, getElementType(), getAlignment()); } /// Return address with different alignment, but same pointer and element /// type. Address withAlignment(CharUnits NewAlignment) const { - return Address(Pointer, ElementType, NewAlignment); + return Address(getPointer(), getElementType(), NewAlignment); } }; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index bacac0a20d4d..9ae5c870afc8 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -197,8 +197,7 @@ public: PassManagerBuilderWrapper(const Triple &TargetTriple, const CodeGenOptions &CGOpts, const LangOptions &LangOpts) - : PassManagerBuilder(), TargetTriple(TargetTriple), CGOpts(CGOpts), - LangOpts(LangOpts) {} + : TargetTriple(TargetTriple), CGOpts(CGOpts), LangOpts(LangOpts) {} const Triple &getTargetTriple() const { return TargetTriple; } const CodeGenOptions &getCGOpts() const { return CGOpts; } const LangOptions &getLangOpts() const { return LangOpts; } @@ -359,7 +358,8 @@ static void addGeneralOptsForMemorySanitizer(const PassManagerBuilder &Builder, int TrackOrigins = CGOpts.SanitizeMemoryTrackOrigins; bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Memory); PM.add(createMemorySanitizerLegacyPassPass( - MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel})); + MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel, + CGOpts.SanitizeMemoryParamRetval != 0})); // MemorySanitizer inserts complex instrumentation that mostly follows // the logic of the original code, but operates on "shadow" values. @@ -645,6 +645,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags, Options.MCOptions.CommandLineArgs = CodeGenOpts.CommandLineArgs; Options.DebugStrictDwarf = CodeGenOpts.DebugStrictDwarf; Options.ObjectFilenameForDebug = CodeGenOpts.ObjectFilenameForDebug; + Options.Hotpatch = CodeGenOpts.HotPatch; return true; } @@ -1164,11 +1165,11 @@ static void addSanitizers(const Triple &TargetTriple, int TrackOrigins = CodeGenOpts.SanitizeMemoryTrackOrigins; bool Recover = CodeGenOpts.SanitizeRecover.has(Mask); - MPM.addPass( - ModuleMemorySanitizerPass({TrackOrigins, Recover, CompileKernel})); + MemorySanitizerOptions options(TrackOrigins, Recover, CompileKernel, + CodeGenOpts.SanitizeMemoryParamRetval); + MPM.addPass(ModuleMemorySanitizerPass(options)); FunctionPassManager FPM; - FPM.addPass( - MemorySanitizerPass({TrackOrigins, Recover, CompileKernel})); + FPM.addPass(MemorySanitizerPass(options)); if (Level != OptimizationLevel::O0) { // MemorySanitizer inserts complex instrumentation that mostly // follows the logic of the original code, but operates on @@ -1491,8 +1492,11 @@ void EmitAssemblyHelper::RunOptimizationPipeline( } // Now that we have all of the passes ready, run them. - PrettyStackTraceString CrashInfo("Optimizer"); - MPM.run(*TheModule, MAM); + { + PrettyStackTraceString CrashInfo("Optimizer"); + llvm::TimeTraceScope TimeScope("Optimizer"); + MPM.run(*TheModule, MAM); + } } void EmitAssemblyHelper::RunCodegenPipeline( @@ -1524,8 +1528,11 @@ void EmitAssemblyHelper::RunCodegenPipeline( return; } - PrettyStackTraceString CrashInfo("Code generation"); - CodeGenPasses.run(*TheModule); + { + PrettyStackTraceString CrashInfo("Code generation"); + llvm::TimeTraceScope TimeScope("CodeGenPasses"); + CodeGenPasses.run(*TheModule); + } } /// A clean version of `EmitAssembly` that uses the new pass manager. diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index e81c5ba5055c..10569ae2c3f9 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -307,7 +307,7 @@ static RValue emitAtomicLibcall(CodeGenFunction &CGF, const CGFunctionInfo &fnInfo = CGF.CGM.getTypes().arrangeBuiltinFunctionCall(resultType, args); llvm::FunctionType *fnTy = CGF.CGM.getTypes().GetFunctionType(fnInfo); - llvm::AttrBuilder fnAttrB; + llvm::AttrBuilder fnAttrB(CGF.getLLVMContext()); fnAttrB.addAttribute(llvm::Attribute::NoUnwind); fnAttrB.addAttribute(llvm::Attribute::WillReturn); llvm::AttributeList fnAttrs = llvm::AttributeList::get( @@ -351,12 +351,12 @@ bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const { bool AtomicInfo::emitMemSetZeroIfNecessary() const { assert(LVal.isSimple()); - llvm::Value *addr = LVal.getPointer(CGF); - if (!requiresMemSetZero(addr->getType()->getPointerElementType())) + Address addr = LVal.getAddress(CGF); + if (!requiresMemSetZero(addr.getElementType())) return false; CGF.Builder.CreateMemSet( - addr, llvm::ConstantInt::get(CGF.Int8Ty, 0), + addr.getPointer(), llvm::ConstantInt::get(CGF.Int8Ty, 0), CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(), LVal.getAlignment().getAsAlign()); return true; @@ -1522,7 +1522,7 @@ RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal, !AsValue)) { auto *ValTy = AsValue ? CGF.ConvertTypeForMem(ValueTy) - : getAtomicAddress().getType()->getPointerElementType(); + : getAtomicAddress().getElementType(); if (ValTy->isIntegerTy()) { assert(IntVal->getType() == ValTy && "Different integer types."); return RValue::get(CGF.EmitFromMemory(IntVal, ValueTy)); diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 7bb6dbb8a8ac..1f1de3df857c 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -33,10 +33,10 @@ using namespace clang; using namespace CodeGen; CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name) - : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false), - HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false), - CapturesNonExternalType(false), LocalAddress(Address::invalid()), - StructureType(nullptr), Block(block) { + : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false), + NoEscape(false), HasCXXObject(false), UsesStret(false), + HasCapturedVariableLayout(false), CapturesNonExternalType(false), + LocalAddress(Address::invalid()), StructureType(nullptr), Block(block) { // Skip asm prefix, if any. 'name' is usually taken directly from // the mangled name of the enclosing function. @@ -66,17 +66,6 @@ static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM, namespace { -/// Represents a type of copy/destroy operation that should be performed for an -/// entity that's captured by a block. -enum class BlockCaptureEntityKind { - CXXRecord, // Copy or destroy - ARCWeak, - ARCStrong, - NonTrivialCStruct, - BlockObject, // Assign or release - None -}; - /// Represents a captured entity that requires extra operations in order for /// this entity to be copied or destroyed correctly. struct BlockCaptureManagedEntity { @@ -110,11 +99,7 @@ enum class CaptureStrKind { } // end anonymous namespace -static void findBlockCapturedManagedEntities( - const CGBlockInfo &BlockInfo, const LangOptions &LangOpts, - SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures); - -static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E, +static std::string getBlockCaptureStr(const CGBlockInfo::Capture &Cap, CaptureStrKind StrKind, CharUnits BlockAlignment, CodeGenModule &CGM); @@ -124,34 +109,33 @@ static std::string getBlockDescriptorName(const CGBlockInfo &BlockInfo, std::string Name = "__block_descriptor_"; Name += llvm::to_string(BlockInfo.BlockSize.getQuantity()) + "_"; - if (BlockInfo.needsCopyDisposeHelpers()) { + if (BlockInfo.NeedsCopyDispose) { if (CGM.getLangOpts().Exceptions) Name += "e"; if (CGM.getCodeGenOpts().ObjCAutoRefCountExceptions) Name += "a"; Name += llvm::to_string(BlockInfo.BlockAlign.getQuantity()) + "_"; - SmallVector<BlockCaptureManagedEntity, 4> ManagedCaptures; - findBlockCapturedManagedEntities(BlockInfo, CGM.getContext().getLangOpts(), - ManagedCaptures); + for (auto &Cap : BlockInfo.SortedCaptures) { + if (Cap.isConstantOrTrivial()) + continue; - for (const BlockCaptureManagedEntity &E : ManagedCaptures) { - Name += llvm::to_string(E.Capture->getOffset().getQuantity()); + Name += llvm::to_string(Cap.getOffset().getQuantity()); - if (E.CopyKind == E.DisposeKind) { + if (Cap.CopyKind == Cap.DisposeKind) { // If CopyKind and DisposeKind are the same, merge the capture // information. - assert(E.CopyKind != BlockCaptureEntityKind::None && + assert(Cap.CopyKind != BlockCaptureEntityKind::None && "shouldn't see BlockCaptureManagedEntity that is None"); - Name += getBlockCaptureStr(E, CaptureStrKind::Merged, + Name += getBlockCaptureStr(Cap, CaptureStrKind::Merged, BlockInfo.BlockAlign, CGM); } else { // If CopyKind and DisposeKind are not the same, which can happen when // either Kind is None or the captured object is a __strong block, // concatenate the copy and dispose strings. - Name += getBlockCaptureStr(E, CaptureStrKind::CopyHelper, + Name += getBlockCaptureStr(Cap, CaptureStrKind::CopyHelper, BlockInfo.BlockAlign, CGM); - Name += getBlockCaptureStr(E, CaptureStrKind::DisposeHelper, + Name += getBlockCaptureStr(Cap, CaptureStrKind::DisposeHelper, BlockInfo.BlockAlign, CGM); } } @@ -223,7 +207,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, // Optional copy/dispose helpers. bool hasInternalHelper = false; - if (blockInfo.needsCopyDisposeHelpers()) { + if (blockInfo.NeedsCopyDispose) { // copy_func_helper_decl llvm::Constant *copyHelper = buildCopyHelper(CGM, blockInfo); elements.add(copyHelper); @@ -340,17 +324,21 @@ namespace { struct BlockLayoutChunk { CharUnits Alignment; CharUnits Size; - Qualifiers::ObjCLifetime Lifetime; const BlockDecl::Capture *Capture; // null for 'this' llvm::Type *Type; QualType FieldType; + BlockCaptureEntityKind CopyKind, DisposeKind; + BlockFieldFlags CopyFlags, DisposeFlags; BlockLayoutChunk(CharUnits align, CharUnits size, - Qualifiers::ObjCLifetime lifetime, - const BlockDecl::Capture *capture, - llvm::Type *type, QualType fieldType) - : Alignment(align), Size(size), Lifetime(lifetime), - Capture(capture), Type(type), FieldType(fieldType) {} + const BlockDecl::Capture *capture, llvm::Type *type, + QualType fieldType, BlockCaptureEntityKind CopyKind, + BlockFieldFlags CopyFlags, + BlockCaptureEntityKind DisposeKind, + BlockFieldFlags DisposeFlags) + : Alignment(align), Size(size), Capture(capture), Type(type), + FieldType(fieldType), CopyKind(CopyKind), DisposeKind(DisposeKind), + CopyFlags(CopyFlags), DisposeFlags(DisposeFlags) {} /// Tell the block info that this chunk has the given field index. void setIndex(CGBlockInfo &info, unsigned index, CharUnits offset) { @@ -358,32 +346,93 @@ namespace { info.CXXThisIndex = index; info.CXXThisOffset = offset; } else { - auto C = CGBlockInfo::Capture::makeIndex(index, offset, FieldType); - info.Captures.insert({Capture->getVariable(), C}); + info.SortedCaptures.push_back(CGBlockInfo::Capture::makeIndex( + index, offset, FieldType, CopyKind, CopyFlags, DisposeKind, + DisposeFlags, Capture)); } } + + bool isTrivial() const { + return CopyKind == BlockCaptureEntityKind::None && + DisposeKind == BlockCaptureEntityKind::None; + } }; - /// Order by 1) all __strong together 2) next, all byfref together 3) next, - /// all __weak together. Preserve descending alignment in all situations. + /// Order by 1) all __strong together 2) next, all block together 3) next, + /// all byref together 4) next, all __weak together. Preserve descending + /// alignment in all situations. bool operator<(const BlockLayoutChunk &left, const BlockLayoutChunk &right) { if (left.Alignment != right.Alignment) return left.Alignment > right.Alignment; auto getPrefOrder = [](const BlockLayoutChunk &chunk) { - if (chunk.Capture && chunk.Capture->isByRef()) - return 1; - if (chunk.Lifetime == Qualifiers::OCL_Strong) + switch (chunk.CopyKind) { + case BlockCaptureEntityKind::ARCStrong: return 0; - if (chunk.Lifetime == Qualifiers::OCL_Weak) - return 2; - return 3; + case BlockCaptureEntityKind::BlockObject: + switch (chunk.CopyFlags.getBitMask()) { + case BLOCK_FIELD_IS_OBJECT: + return 0; + case BLOCK_FIELD_IS_BLOCK: + return 1; + case BLOCK_FIELD_IS_BYREF: + return 2; + default: + break; + } + break; + case BlockCaptureEntityKind::ARCWeak: + return 3; + default: + break; + } + return 4; }; return getPrefOrder(left) < getPrefOrder(right); } } // end anonymous namespace +static std::pair<BlockCaptureEntityKind, BlockFieldFlags> +computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, + const LangOptions &LangOpts); + +static std::pair<BlockCaptureEntityKind, BlockFieldFlags> +computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, + const LangOptions &LangOpts); + +static void addBlockLayout(CharUnits align, CharUnits size, + const BlockDecl::Capture *capture, llvm::Type *type, + QualType fieldType, + SmallVectorImpl<BlockLayoutChunk> &Layout, + CGBlockInfo &Info, CodeGenModule &CGM) { + if (!capture) { + // 'this' capture. + Layout.push_back(BlockLayoutChunk( + align, size, capture, type, fieldType, BlockCaptureEntityKind::None, + BlockFieldFlags(), BlockCaptureEntityKind::None, BlockFieldFlags())); + return; + } + + const LangOptions &LangOpts = CGM.getLangOpts(); + BlockCaptureEntityKind CopyKind, DisposeKind; + BlockFieldFlags CopyFlags, DisposeFlags; + + std::tie(CopyKind, CopyFlags) = + computeCopyInfoForBlockCapture(*capture, fieldType, LangOpts); + std::tie(DisposeKind, DisposeFlags) = + computeDestroyInfoForBlockCapture(*capture, fieldType, LangOpts); + Layout.push_back(BlockLayoutChunk(align, size, capture, type, fieldType, + CopyKind, CopyFlags, DisposeKind, + DisposeFlags)); + + if (Info.NoEscape) + return; + + if (!Layout.back().isTrivial()) + Info.NeedsCopyDispose = true; +} + /// Determines if the given type is safe for constant capture in C++. static bool isSafeForCXXConstantCapture(QualType type) { const RecordType *recordType = @@ -541,6 +590,9 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, CGM.getLangOpts().getGC() == LangOptions::NonGC) info.HasCapturedVariableLayout = true; + if (block->doesNotEscape()) + info.NoEscape = true; + // Collect the layout chunks. SmallVector<BlockLayoutChunk, 16> layout; layout.reserve(block->capturesCXXThis() + @@ -560,9 +612,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, auto TInfo = CGM.getContext().getTypeInfoInChars(thisType); maxFieldAlign = std::max(maxFieldAlign, TInfo.Align); - layout.push_back(BlockLayoutChunk(TInfo.Align, TInfo.Width, - Qualifiers::OCL_None, - nullptr, llvmType, thisType)); + addBlockLayout(TInfo.Align, TInfo.Width, nullptr, llvmType, thisType, + layout, info, CGM); } // Next, all the block captures. @@ -570,9 +621,6 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, const VarDecl *variable = CI.getVariable(); if (CI.isEscapingByref()) { - // We have to copy/dispose of the __block reference. - info.NeedsCopyDispose = true; - // Just use void* instead of a pointer to the byref type. CharUnits align = CGM.getPointerAlign(); maxFieldAlign = std::max(maxFieldAlign, align); @@ -581,72 +629,28 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, // the capture field type should always match. assert(CGF && getCaptureFieldType(*CGF, CI) == variable->getType() && "capture type differs from the variable type"); - layout.push_back(BlockLayoutChunk(align, CGM.getPointerSize(), - Qualifiers::OCL_None, &CI, - CGM.VoidPtrTy, variable->getType())); + addBlockLayout(align, CGM.getPointerSize(), &CI, CGM.VoidPtrTy, + variable->getType(), layout, info, CGM); continue; } // Otherwise, build a layout chunk with the size and alignment of // the declaration. if (llvm::Constant *constant = tryCaptureAsConstant(CGM, CGF, variable)) { - info.Captures[variable] = CGBlockInfo::Capture::makeConstant(constant); + info.SortedCaptures.push_back( + CGBlockInfo::Capture::makeConstant(constant, &CI)); continue; } QualType VT = getCaptureFieldType(*CGF, CI); - // If we have a lifetime qualifier, honor it for capture purposes. - // That includes *not* copying it if it's __unsafe_unretained. - Qualifiers::ObjCLifetime lifetime = VT.getObjCLifetime(); - if (lifetime) { - switch (lifetime) { - case Qualifiers::OCL_None: llvm_unreachable("impossible"); - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Autoreleasing: - break; - - case Qualifiers::OCL_Strong: - case Qualifiers::OCL_Weak: - info.NeedsCopyDispose = true; - } - - // Block pointers require copy/dispose. So do Objective-C pointers. - } else if (VT->isObjCRetainableType()) { - // But honor the inert __unsafe_unretained qualifier, which doesn't - // actually make it into the type system. - if (VT->isObjCInertUnsafeUnretainedType()) { - lifetime = Qualifiers::OCL_ExplicitNone; - } else { - info.NeedsCopyDispose = true; - // used for mrr below. - lifetime = Qualifiers::OCL_Strong; - } - - // So do types that require non-trivial copy construction. - } else if (CI.hasCopyExpr()) { - info.NeedsCopyDispose = true; - info.HasCXXObject = true; - if (!VT->getAsCXXRecordDecl()->isExternallyVisible()) - info.CapturesNonExternalType = true; - - // So do C structs that require non-trivial copy construction or - // destruction. - } else if (VT.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct || - VT.isDestructedType() == QualType::DK_nontrivial_c_struct) { - info.NeedsCopyDispose = true; - - // And so do types with destructors. - } else if (CGM.getLangOpts().CPlusPlus) { - if (const CXXRecordDecl *record = VT->getAsCXXRecordDecl()) { - if (!record->hasTrivialDestructor()) { + if (CGM.getLangOpts().CPlusPlus) + if (const CXXRecordDecl *record = VT->getAsCXXRecordDecl()) + if (CI.hasCopyExpr() || !record->hasTrivialDestructor()) { info.HasCXXObject = true; - info.NeedsCopyDispose = true; if (!record->isExternallyVisible()) info.CapturesNonExternalType = true; } - } - } CharUnits size = C.getTypeSizeInChars(VT); CharUnits align = C.getDeclAlign(variable); @@ -656,8 +660,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, llvm::Type *llvmType = CGM.getTypes().ConvertTypeForMem(VT); - layout.push_back( - BlockLayoutChunk(align, size, lifetime, &CI, llvmType, VT)); + addBlockLayout(align, size, &CI, llvmType, VT, layout, info, CGM); } // If that was everything, we're done here. @@ -665,6 +668,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, info.StructureType = llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true); info.CanBeGlobal = true; + info.buildCaptureMap(); return; } @@ -718,6 +722,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, // ...until we get to the alignment of the maximum field. if (endAlign >= maxFieldAlign) { + ++li; break; } } @@ -770,6 +775,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, endAlign = getLowBit(blockSize); } + info.buildCaptureMap(); info.StructureType = llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true); } @@ -826,7 +832,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // If the block is non-escaping, set field 'isa 'to NSConcreteGlobalBlock // and set the BLOCK_IS_GLOBAL bit of field 'flags'. Copying a non-escaping // block just returns the original block and releasing it is a no-op. - llvm::Constant *blockISA = blockInfo.getBlockDecl()->doesNotEscape() + llvm::Constant *blockISA = blockInfo.NoEscape ? CGM.getNSConcreteGlobalBlock() : CGM.getNSConcreteStackBlock(); isa = llvm::ConstantExpr::getBitCast(blockISA, VoidPtrTy); @@ -838,13 +844,13 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { flags = BLOCK_HAS_SIGNATURE; if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT; - if (blockInfo.needsCopyDisposeHelpers()) + if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ; if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; - if (blockInfo.getBlockDecl()->doesNotEscape()) + if (blockInfo.NoEscape) flags |= BLOCK_IS_NOESCAPE | BLOCK_IS_GLOBAL; } @@ -1033,7 +1039,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { } // Push a cleanup for the capture if necessary. - if (!blockInfo.NeedsCopyDispose) + if (!blockInfo.NoEscape && !blockInfo.NeedsCopyDispose) continue; // Ignore __block captures; there's nothing special in the on-stack block @@ -1654,6 +1660,11 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, // For all other types, the memcpy is fine. return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags()); + // Honor the inert __unsafe_unretained qualifier, which doesn't actually + // make it into the type system. + if (T->isObjCInertUnsafeUnretainedType()) + return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags()); + // Special rules for ARC captures: Qualifiers QS = T.getQualifiers(); @@ -1669,34 +1680,6 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, llvm_unreachable("after exhaustive PrimitiveCopyKind switch"); } -static std::pair<BlockCaptureEntityKind, BlockFieldFlags> -computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, - const LangOptions &LangOpts); - -/// Find the set of block captures that need to be explicitly copied or destroy. -static void findBlockCapturedManagedEntities( - const CGBlockInfo &BlockInfo, const LangOptions &LangOpts, - SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures) { - for (const auto &CI : BlockInfo.getBlockDecl()->captures()) { - const VarDecl *Variable = CI.getVariable(); - const CGBlockInfo::Capture &Capture = BlockInfo.getCapture(Variable); - if (Capture.isConstant()) - continue; - - QualType VT = Capture.fieldType(); - auto CopyInfo = computeCopyInfoForBlockCapture(CI, VT, LangOpts); - auto DisposeInfo = computeDestroyInfoForBlockCapture(CI, VT, LangOpts); - if (CopyInfo.first != BlockCaptureEntityKind::None || - DisposeInfo.first != BlockCaptureEntityKind::None) - ManagedCaptures.emplace_back(CopyInfo.first, DisposeInfo.first, - CopyInfo.second, DisposeInfo.second, CI, - Capture); - } - - // Sort the captures by offset. - llvm::sort(ManagedCaptures); -} - namespace { /// Release a __block variable. struct CallBlockRelease final : EHScopeStack::Cleanup { @@ -1732,13 +1715,13 @@ bool CodeGenFunction::cxxDestructorCanThrow(QualType T) { } // Return a string that has the information about a capture. -static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E, +static std::string getBlockCaptureStr(const CGBlockInfo::Capture &Cap, CaptureStrKind StrKind, CharUnits BlockAlignment, CodeGenModule &CGM) { std::string Str; ASTContext &Ctx = CGM.getContext(); - const BlockDecl::Capture &CI = *E.CI; + const BlockDecl::Capture &CI = *Cap.Cap; QualType CaptureTy = CI.getVariable()->getType(); BlockCaptureEntityKind Kind; @@ -1747,15 +1730,16 @@ static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E, // CaptureStrKind::Merged should be passed only when the operations and the // flags are the same for copy and dispose. assert((StrKind != CaptureStrKind::Merged || - (E.CopyKind == E.DisposeKind && E.CopyFlags == E.DisposeFlags)) && + (Cap.CopyKind == Cap.DisposeKind && + Cap.CopyFlags == Cap.DisposeFlags)) && "different operations and flags"); if (StrKind == CaptureStrKind::DisposeHelper) { - Kind = E.DisposeKind; - Flags = E.DisposeFlags; + Kind = Cap.DisposeKind; + Flags = Cap.DisposeFlags; } else { - Kind = E.CopyKind; - Flags = E.CopyFlags; + Kind = Cap.CopyKind; + Flags = Cap.CopyFlags; } switch (Kind) { @@ -1803,8 +1787,7 @@ static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E, } case BlockCaptureEntityKind::NonTrivialCStruct: { bool IsVolatile = CaptureTy.isVolatileQualified(); - CharUnits Alignment = - BlockAlignment.alignmentAtOffset(E.Capture->getOffset()); + CharUnits Alignment = BlockAlignment.alignmentAtOffset(Cap.getOffset()); Str += "n"; std::string FuncStr; @@ -1829,7 +1812,7 @@ static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E, } static std::string getCopyDestroyHelperFuncName( - const SmallVectorImpl<BlockCaptureManagedEntity> &Captures, + const SmallVectorImpl<CGBlockInfo::Capture> &Captures, CharUnits BlockAlignment, CaptureStrKind StrKind, CodeGenModule &CGM) { assert((StrKind == CaptureStrKind::CopyHelper || StrKind == CaptureStrKind::DisposeHelper) && @@ -1843,9 +1826,11 @@ static std::string getCopyDestroyHelperFuncName( Name += "a"; Name += llvm::to_string(BlockAlignment.getQuantity()) + "_"; - for (const BlockCaptureManagedEntity &E : Captures) { - Name += llvm::to_string(E.Capture->getOffset().getQuantity()); - Name += getBlockCaptureStr(E, StrKind, BlockAlignment, CGM); + for (auto &Cap : Captures) { + if (Cap.isConstantOrTrivial()) + continue; + Name += llvm::to_string(Cap.getOffset().getQuantity()); + Name += getBlockCaptureStr(Cap, StrKind, BlockAlignment, CGM); } return Name; @@ -1916,11 +1901,9 @@ static void setBlockHelperAttributesVisibility(bool CapturesNonExternalType, /// the contents of an individual __block variable to the heap. llvm::Constant * CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { - SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures; - findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures); - std::string FuncName = - getCopyDestroyHelperFuncName(CopiedCaptures, blockInfo.BlockAlign, - CaptureStrKind::CopyHelper, CGM); + std::string FuncName = getCopyDestroyHelperFuncName( + blockInfo.SortedCaptures, blockInfo.BlockAlign, + CaptureStrKind::CopyHelper, CGM); if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName)) return llvm::ConstantExpr::getBitCast(Func, VoidPtrTy); @@ -1967,17 +1950,19 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign); dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest"); - for (const auto &CopiedCapture : CopiedCaptures) { - const BlockDecl::Capture &CI = *CopiedCapture.CI; - const CGBlockInfo::Capture &capture = *CopiedCapture.Capture; + for (auto &capture : blockInfo.SortedCaptures) { + if (capture.isConstantOrTrivial()) + continue; + + const BlockDecl::Capture &CI = *capture.Cap; QualType captureType = CI.getVariable()->getType(); - BlockFieldFlags flags = CopiedCapture.CopyFlags; + BlockFieldFlags flags = capture.CopyFlags; unsigned index = capture.getIndex(); Address srcField = Builder.CreateStructGEP(src, index); Address dstField = Builder.CreateStructGEP(dst, index); - switch (CopiedCapture.CopyKind) { + switch (capture.CopyKind) { case BlockCaptureEntityKind::CXXRecord: // If there's an explicit copy expression, we do that. assert(CI.getCopyExpr() && "copy expression for variable is missing"); @@ -2040,7 +2025,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { // Ensure that we destroy the copied object if an exception is thrown later // in the helper function. - pushCaptureCleanup(CopiedCapture.CopyKind, dstField, captureType, flags, + pushCaptureCleanup(capture.CopyKind, dstField, captureType, flags, /*ForCopyHelper*/ true, CI.getVariable(), *this); } @@ -2085,8 +2070,10 @@ computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, BlockFieldFlags()); case QualType::DK_none: { // Non-ARC captures are strong, and we need to use _Block_object_dispose. + // But honor the inert __unsafe_unretained qualifier, which doesn't actually + // make it into the type system. if (T->isObjCRetainableType() && !T.getQualifiers().hasObjCLifetime() && - !LangOpts.ObjCAutoRefCount) + !LangOpts.ObjCAutoRefCount && !T->isObjCInertUnsafeUnretainedType()) return std::make_pair(BlockCaptureEntityKind::BlockObject, getBlockFieldFlagsForObjCObjectPointer(CI, T)); // Otherwise, we have nothing to do. @@ -2105,11 +2092,9 @@ computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, /// variable. llvm::Constant * CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { - SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures; - findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures); - std::string FuncName = - getCopyDestroyHelperFuncName(DestroyedCaptures, blockInfo.BlockAlign, - CaptureStrKind::DisposeHelper, CGM); + std::string FuncName = getCopyDestroyHelperFuncName( + blockInfo.SortedCaptures, blockInfo.BlockAlign, + CaptureStrKind::DisposeHelper, CGM); if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName)) return llvm::ConstantExpr::getBitCast(Func, VoidPtrTy); @@ -2153,14 +2138,16 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { CodeGenFunction::RunCleanupsScope cleanups(*this); - for (const auto &DestroyedCapture : DestroyedCaptures) { - const BlockDecl::Capture &CI = *DestroyedCapture.CI; - const CGBlockInfo::Capture &capture = *DestroyedCapture.Capture; - BlockFieldFlags flags = DestroyedCapture.DisposeFlags; + for (auto &capture : blockInfo.SortedCaptures) { + if (capture.isConstantOrTrivial()) + continue; + + const BlockDecl::Capture &CI = *capture.Cap; + BlockFieldFlags flags = capture.DisposeFlags; Address srcField = Builder.CreateStructGEP(src, capture.getIndex()); - pushCaptureCleanup(DestroyedCapture.DisposeKind, srcField, + pushCaptureCleanup(capture.DisposeKind, srcField, CI.getVariable()->getType(), flags, /*ForCopyHelper*/ false, CI.getVariable(), *this); } diff --git a/clang/lib/CodeGen/CGBlocks.h b/clang/lib/CodeGen/CGBlocks.h index 698ecd3d926a..e8857d98894f 100644 --- a/clang/lib/CodeGen/CGBlocks.h +++ b/clang/lib/CodeGen/CGBlocks.h @@ -26,14 +26,7 @@ #include "clang/Basic/TargetInfo.h" namespace llvm { -class Constant; -class Function; -class GlobalValue; -class DataLayout; -class FunctionType; -class PointerType; class Value; -class LLVMContext; } namespace clang { @@ -148,6 +141,17 @@ public: CharUnits FieldOffset; }; +/// Represents a type of copy/destroy operation that should be performed for an +/// entity that's captured by a block. +enum class BlockCaptureEntityKind { + None, + CXXRecord, // Copy or destroy + ARCWeak, + ARCStrong, + NonTrivialCStruct, + BlockObject, // Assign or release +}; + /// CGBlockInfo - Information to generate a block literal. class CGBlockInfo { public: @@ -197,20 +201,40 @@ public: return FieldType; } - static Capture makeIndex(unsigned index, CharUnits offset, - QualType FieldType) { + static Capture + makeIndex(unsigned index, CharUnits offset, QualType FieldType, + BlockCaptureEntityKind CopyKind, BlockFieldFlags CopyFlags, + BlockCaptureEntityKind DisposeKind, BlockFieldFlags DisposeFlags, + const BlockDecl::Capture *Cap) { Capture v; v.Data = (index << 1) | 1; v.Offset = offset.getQuantity(); v.FieldType = FieldType; + v.CopyKind = CopyKind; + v.CopyFlags = CopyFlags; + v.DisposeKind = DisposeKind; + v.DisposeFlags = DisposeFlags; + v.Cap = Cap; return v; } - static Capture makeConstant(llvm::Value *value) { + static Capture makeConstant(llvm::Value *value, + const BlockDecl::Capture *Cap) { Capture v; v.Data = reinterpret_cast<uintptr_t>(value); + v.Cap = Cap; return v; } + + bool isConstantOrTrivial() const { + return CopyKind == BlockCaptureEntityKind::None && + DisposeKind == BlockCaptureEntityKind::None; + } + + BlockCaptureEntityKind CopyKind = BlockCaptureEntityKind::None, + DisposeKind = BlockCaptureEntityKind::None; + BlockFieldFlags CopyFlags, DisposeFlags; + const BlockDecl::Capture *Cap; }; /// CanBeGlobal - True if the block can be global, i.e. it has @@ -221,6 +245,9 @@ public: /// dispose helper functions if the block were escaping. bool NeedsCopyDispose : 1; + /// Indicates whether the block is non-escaping. + bool NoEscape : 1; + /// HasCXXObject - True if the block's custom copy/dispose functions /// need to be run even in GC mode. bool HasCXXObject : 1; @@ -238,8 +265,11 @@ public: /// functions. bool CapturesNonExternalType : 1; - /// The mapping of allocated indexes within the block. - llvm::DenseMap<const VarDecl*, Capture> Captures; + /// Mapping from variables to pointers to captures in SortedCaptures. + llvm::DenseMap<const VarDecl *, Capture *> Captures; + + /// The block's captures. Non-constant captures are sorted by their offsets. + llvm::SmallVector<Capture, 4> SortedCaptures; Address LocalAddress; llvm::StructType *StructureType; @@ -263,14 +293,18 @@ public: /// has been encountered. CGBlockInfo *NextBlockInfo; + void buildCaptureMap() { + for (auto &C : SortedCaptures) + Captures[C.Cap->getVariable()] = &C; + } + const Capture &getCapture(const VarDecl *var) const { return const_cast<CGBlockInfo*>(this)->getCapture(var); } Capture &getCapture(const VarDecl *var) { - llvm::DenseMap<const VarDecl*, Capture>::iterator - it = Captures.find(var); + auto it = Captures.find(var); assert(it != Captures.end() && "no entry for variable!"); - return it->second; + return *it->second; } const BlockDecl *getBlockDecl() const { return Block; } @@ -281,11 +315,6 @@ public: } CGBlockInfo(const BlockDecl *blockDecl, StringRef Name); - - // Indicates whether the block needs a custom copy or dispose function. - bool needsCopyDisposeHelpers() const { - return NeedsCopyDispose && !Block->doesNotEscape(); - } }; } // end namespace CodeGen diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 1982b40ff667..2b7862e618bd 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -159,6 +159,7 @@ static Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V, static Value *MakeBinaryAtomicValue( CodeGenFunction &CGF, llvm::AtomicRMWInst::BinOp Kind, const CallExpr *E, AtomicOrdering Ordering = AtomicOrdering::SequentiallyConsistent) { + QualType T = E->getType(); assert(E->getArg(0)->getType()->isPointerType()); assert(CGF.getContext().hasSameUnqualifiedType(T, @@ -532,13 +533,13 @@ static Value *emitCallMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. -static Value *emitUnaryBuiltin(CodeGenFunction &CGF, - const CallExpr *E, - unsigned IntrinsicID) { +static Value *emitUnaryBuiltin(CodeGenFunction &CGF, const CallExpr *E, + unsigned IntrinsicID, + llvm::StringRef Name = "") { llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); - return CGF.Builder.CreateCall(F, Src0); + return CGF.Builder.CreateCall(F, Src0, Name); } // Emit an intrinsic that has 2 operands of the same type as its result. @@ -1060,7 +1061,10 @@ static llvm::Value *emitPPCLoadReserveIntrinsic(CodeGenFunction &CGF, llvm::InlineAsm *IA = llvm::InlineAsm::get(FTy, Asm, Constraints, /*hasSideEffects=*/true); - return CGF.Builder.CreateCall(IA, {Addr}); + llvm::CallInst *CI = CGF.Builder.CreateCall(IA, {Addr}); + CI->addParamAttr( + 0, Attribute::get(CGF.getLLVMContext(), Attribute::ElementType, RetType)); + return CI; } namespace { @@ -3122,24 +3126,34 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, } case Builtin::BI__builtin_elementwise_abs: { - Value *Op0 = EmitScalarExpr(E->getArg(0)); Value *Result; - if (Op0->getType()->isIntOrIntVectorTy()) + QualType QT = E->getArg(0)->getType(); + + if (auto *VecTy = QT->getAs<VectorType>()) + QT = VecTy->getElementType(); + if (QT->isIntegerType()) Result = Builder.CreateBinaryIntrinsic( - llvm::Intrinsic::abs, Op0, Builder.getFalse(), nullptr, "elt.abs"); + llvm::Intrinsic::abs, EmitScalarExpr(E->getArg(0)), + Builder.getFalse(), nullptr, "elt.abs"); else - Result = Builder.CreateUnaryIntrinsic(llvm::Intrinsic::fabs, Op0, nullptr, - "elt.abs"); - return RValue::get(Result); - } + Result = emitUnaryBuiltin(*this, E, llvm::Intrinsic::fabs, "elt.abs"); - case Builtin::BI__builtin_elementwise_ceil: { - Value *Op0 = EmitScalarExpr(E->getArg(0)); - Value *Result = Builder.CreateUnaryIntrinsic(llvm::Intrinsic::ceil, Op0, - nullptr, "elt.ceil"); return RValue::get(Result); } + case Builtin::BI__builtin_elementwise_ceil: + return RValue::get( + emitUnaryBuiltin(*this, E, llvm::Intrinsic::ceil, "elt.ceil")); + case Builtin::BI__builtin_elementwise_floor: + return RValue::get( + emitUnaryBuiltin(*this, E, llvm::Intrinsic::floor, "elt.floor")); + case Builtin::BI__builtin_elementwise_roundeven: + return RValue::get(emitUnaryBuiltin(*this, E, llvm::Intrinsic::roundeven, + "elt.roundeven")); + case Builtin::BI__builtin_elementwise_trunc: + return RValue::get( + emitUnaryBuiltin(*this, E, llvm::Intrinsic::trunc, "elt.trunc")); + case Builtin::BI__builtin_elementwise_max: { Value *Op0 = EmitScalarExpr(E->getArg(0)); Value *Op1 = EmitScalarExpr(E->getArg(1)); @@ -3174,52 +3188,48 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, } case Builtin::BI__builtin_reduce_max: { - auto GetIntrinsicID = [](QualType QT, llvm::Type *IrTy) { - if (IrTy->isIntOrIntVectorTy()) { - if (auto *VecTy = QT->getAs<VectorType>()) - QT = VecTy->getElementType(); - if (QT->isSignedIntegerType()) - return llvm::Intrinsic::vector_reduce_smax; - else - return llvm::Intrinsic::vector_reduce_umax; - } + auto GetIntrinsicID = [](QualType QT) { + if (auto *VecTy = QT->getAs<VectorType>()) + QT = VecTy->getElementType(); + if (QT->isSignedIntegerType()) + return llvm::Intrinsic::vector_reduce_smax; + if (QT->isUnsignedIntegerType()) + return llvm::Intrinsic::vector_reduce_umax; + assert(QT->isFloatingType() && "must have a float here"); return llvm::Intrinsic::vector_reduce_fmax; }; - Value *Op0 = EmitScalarExpr(E->getArg(0)); - Value *Result = Builder.CreateUnaryIntrinsic( - GetIntrinsicID(E->getArg(0)->getType(), Op0->getType()), Op0, nullptr, - "rdx.min"); - return RValue::get(Result); + return RValue::get(emitUnaryBuiltin( + *this, E, GetIntrinsicID(E->getArg(0)->getType()), "rdx.min")); } case Builtin::BI__builtin_reduce_min: { - auto GetIntrinsicID = [](QualType QT, llvm::Type *IrTy) { - if (IrTy->isIntOrIntVectorTy()) { - if (auto *VecTy = QT->getAs<VectorType>()) - QT = VecTy->getElementType(); - if (QT->isSignedIntegerType()) - return llvm::Intrinsic::vector_reduce_smin; - else - return llvm::Intrinsic::vector_reduce_umin; - } + auto GetIntrinsicID = [](QualType QT) { + if (auto *VecTy = QT->getAs<VectorType>()) + QT = VecTy->getElementType(); + if (QT->isSignedIntegerType()) + return llvm::Intrinsic::vector_reduce_smin; + if (QT->isUnsignedIntegerType()) + return llvm::Intrinsic::vector_reduce_umin; + assert(QT->isFloatingType() && "must have a float here"); return llvm::Intrinsic::vector_reduce_fmin; }; - Value *Op0 = EmitScalarExpr(E->getArg(0)); - Value *Result = Builder.CreateUnaryIntrinsic( - GetIntrinsicID(E->getArg(0)->getType(), Op0->getType()), Op0, nullptr, - "rdx.min"); - return RValue::get(Result); - } - case Builtin::BI__builtin_reduce_xor: { - Value *Op0 = EmitScalarExpr(E->getArg(0)); - Value *Result = Builder.CreateUnaryIntrinsic( - llvm::Intrinsic::vector_reduce_xor, Op0, nullptr, "rdx.xor"); - return RValue::get(Result); + return RValue::get(emitUnaryBuiltin( + *this, E, GetIntrinsicID(E->getArg(0)->getType()), "rdx.min")); } + case Builtin::BI__builtin_reduce_xor: + return RValue::get(emitUnaryBuiltin( + *this, E, llvm::Intrinsic::vector_reduce_xor, "rdx.xor")); + case Builtin::BI__builtin_reduce_or: + return RValue::get(emitUnaryBuiltin( + *this, E, llvm::Intrinsic::vector_reduce_or, "rdx.or")); + case Builtin::BI__builtin_reduce_and: + return RValue::get(emitUnaryBuiltin( + *this, E, llvm::Intrinsic::vector_reduce_and, "rdx.and")); + case Builtin::BI__builtin_matrix_transpose: { - const auto *MatrixTy = E->getArg(0)->getType()->getAs<ConstantMatrixType>(); + auto *MatrixTy = E->getArg(0)->getType()->castAs<ConstantMatrixType>(); Value *MatValue = EmitScalarExpr(E->getArg(0)); MatrixBuilder<CGBuilderTy> MB(Builder); Value *Result = MB.CreateMatrixTranspose(MatValue, MatrixTy->getNumRows(), @@ -3423,6 +3433,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BIalloca: case Builtin::BI_alloca: + case Builtin::BI__builtin_alloca_uninitialized: case Builtin::BI__builtin_alloca: { Value *Size = EmitScalarExpr(E->getArg(0)); const TargetInfo &TI = getContext().getTargetInfo(); @@ -3433,10 +3444,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, .getAsAlign(); AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size); AI->setAlignment(SuitableAlignmentInBytes); - initializeAlloca(*this, AI, Size, SuitableAlignmentInBytes); + if (BuiltinID != Builtin::BI__builtin_alloca_uninitialized) + initializeAlloca(*this, AI, Size, SuitableAlignmentInBytes); return RValue::get(AI); } + case Builtin::BI__builtin_alloca_with_align_uninitialized: case Builtin::BI__builtin_alloca_with_align: { Value *Size = EmitScalarExpr(E->getArg(0)); Value *AlignmentInBitsValue = EmitScalarExpr(E->getArg(1)); @@ -3446,7 +3459,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, CGM.getContext().toCharUnitsFromBits(AlignmentInBits).getAsAlign(); AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size); AI->setAlignment(AlignmentInBytes); - initializeAlloca(*this, AI, Size, AlignmentInBytes); + if (BuiltinID != Builtin::BI__builtin_alloca_with_align_uninitialized) + initializeAlloca(*this, AI, Size, AlignmentInBytes); return RValue::get(AI); } @@ -4921,7 +4935,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Value *Block = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy); - AttrBuilder B; + AttrBuilder B(Builder.getContext()); B.addByValAttr(NDRangeL.getAddress(*this).getElementType()); llvm::AttributeList ByValAttrSet = llvm::AttributeList::get(CGM.getModule().getContext(), 3U, B); @@ -5860,6 +5874,10 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = { NEONMAP1(vqmovun_v, arm_neon_vqmovnsu, Add1ArgType), NEONMAP1(vqneg_v, arm_neon_vqneg, Add1ArgType), NEONMAP1(vqnegq_v, arm_neon_vqneg, Add1ArgType), + NEONMAP1(vqrdmlah_v, arm_neon_vqrdmlah, Add1ArgType), + NEONMAP1(vqrdmlahq_v, arm_neon_vqrdmlah, Add1ArgType), + NEONMAP1(vqrdmlsh_v, arm_neon_vqrdmlsh, Add1ArgType), + NEONMAP1(vqrdmlshq_v, arm_neon_vqrdmlsh, Add1ArgType), NEONMAP1(vqrdmulh_v, arm_neon_vqrdmulh, Add1ArgType), NEONMAP1(vqrdmulhq_v, arm_neon_vqrdmulh, Add1ArgType), NEONMAP2(vqrshl_v, arm_neon_vqrshiftu, arm_neon_vqrshifts, Add1ArgType | UnsignedAlts), @@ -6085,6 +6103,10 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = { NEONMAP1(vqmovun_v, aarch64_neon_sqxtun, Add1ArgType), NEONMAP1(vqneg_v, aarch64_neon_sqneg, Add1ArgType), NEONMAP1(vqnegq_v, aarch64_neon_sqneg, Add1ArgType), + NEONMAP1(vqrdmlah_v, aarch64_neon_sqrdmlah, Add1ArgType), + NEONMAP1(vqrdmlahq_v, aarch64_neon_sqrdmlah, Add1ArgType), + NEONMAP1(vqrdmlsh_v, aarch64_neon_sqrdmlsh, Add1ArgType), + NEONMAP1(vqrdmlshq_v, aarch64_neon_sqrdmlsh, Add1ArgType), NEONMAP1(vqrdmulh_lane_v, aarch64_neon_sqrdmulh_lane, 0), NEONMAP1(vqrdmulh_laneq_v, aarch64_neon_sqrdmulh_laneq, 0), NEONMAP1(vqrdmulh_v, aarch64_neon_sqrdmulh, Add1ArgType), @@ -6287,6 +6309,10 @@ static const ARMVectorIntrinsicInfo AArch64SISDIntrinsicMap[] = { NEONMAP1(vqnegd_s64, aarch64_neon_sqneg, Add1ArgType), NEONMAP1(vqnegh_s16, aarch64_neon_sqneg, Vectorize1ArgType | Use64BitVectors), NEONMAP1(vqnegs_s32, aarch64_neon_sqneg, Add1ArgType), + NEONMAP1(vqrdmlahh_s16, aarch64_neon_sqrdmlah, Vectorize1ArgType | Use64BitVectors), + NEONMAP1(vqrdmlahs_s32, aarch64_neon_sqrdmlah, Add1ArgType), + NEONMAP1(vqrdmlshh_s16, aarch64_neon_sqrdmlsh, Vectorize1ArgType | Use64BitVectors), + NEONMAP1(vqrdmlshs_s32, aarch64_neon_sqrdmlsh, Add1ArgType), NEONMAP1(vqrdmulhh_s16, aarch64_neon_sqrdmulh, Vectorize1ArgType | Use64BitVectors), NEONMAP1(vqrdmulhs_s32, aarch64_neon_sqrdmulh, Add1ArgType), NEONMAP1(vqrshlb_s8, aarch64_neon_sqrshl, Vectorize1ArgType | Use64BitVectors), @@ -14271,73 +14297,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F, Ops[0]); } } - case X86::BI__builtin_ia32_pabsb128: - case X86::BI__builtin_ia32_pabsw128: - case X86::BI__builtin_ia32_pabsd128: - case X86::BI__builtin_ia32_pabsb256: - case X86::BI__builtin_ia32_pabsw256: - case X86::BI__builtin_ia32_pabsd256: - case X86::BI__builtin_ia32_pabsq128: - case X86::BI__builtin_ia32_pabsq256: - case X86::BI__builtin_ia32_pabsb512: - case X86::BI__builtin_ia32_pabsw512: - case X86::BI__builtin_ia32_pabsd512: - case X86::BI__builtin_ia32_pabsq512: { - Function *F = CGM.getIntrinsic(Intrinsic::abs, Ops[0]->getType()); - return Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)}); - } - case X86::BI__builtin_ia32_pmaxsb128: - case X86::BI__builtin_ia32_pmaxsw128: - case X86::BI__builtin_ia32_pmaxsd128: - case X86::BI__builtin_ia32_pmaxsq128: - case X86::BI__builtin_ia32_pmaxsb256: - case X86::BI__builtin_ia32_pmaxsw256: - case X86::BI__builtin_ia32_pmaxsd256: - case X86::BI__builtin_ia32_pmaxsq256: - case X86::BI__builtin_ia32_pmaxsb512: - case X86::BI__builtin_ia32_pmaxsw512: - case X86::BI__builtin_ia32_pmaxsd512: - case X86::BI__builtin_ia32_pmaxsq512: - return EmitX86BinaryIntrinsic(*this, Ops, Intrinsic::smax); - case X86::BI__builtin_ia32_pmaxub128: - case X86::BI__builtin_ia32_pmaxuw128: - case X86::BI__builtin_ia32_pmaxud128: - case X86::BI__builtin_ia32_pmaxuq128: - case X86::BI__builtin_ia32_pmaxub256: - case X86::BI__builtin_ia32_pmaxuw256: - case X86::BI__builtin_ia32_pmaxud256: - case X86::BI__builtin_ia32_pmaxuq256: - case X86::BI__builtin_ia32_pmaxub512: - case X86::BI__builtin_ia32_pmaxuw512: - case X86::BI__builtin_ia32_pmaxud512: - case X86::BI__builtin_ia32_pmaxuq512: - return EmitX86BinaryIntrinsic(*this, Ops, Intrinsic::umax); - case X86::BI__builtin_ia32_pminsb128: - case X86::BI__builtin_ia32_pminsw128: - case X86::BI__builtin_ia32_pminsd128: - case X86::BI__builtin_ia32_pminsq128: - case X86::BI__builtin_ia32_pminsb256: - case X86::BI__builtin_ia32_pminsw256: - case X86::BI__builtin_ia32_pminsd256: - case X86::BI__builtin_ia32_pminsq256: - case X86::BI__builtin_ia32_pminsb512: - case X86::BI__builtin_ia32_pminsw512: - case X86::BI__builtin_ia32_pminsd512: - case X86::BI__builtin_ia32_pminsq512: - return EmitX86BinaryIntrinsic(*this, Ops, Intrinsic::smin); - case X86::BI__builtin_ia32_pminub128: - case X86::BI__builtin_ia32_pminuw128: - case X86::BI__builtin_ia32_pminud128: - case X86::BI__builtin_ia32_pminuq128: - case X86::BI__builtin_ia32_pminub256: - case X86::BI__builtin_ia32_pminuw256: - case X86::BI__builtin_ia32_pminud256: - case X86::BI__builtin_ia32_pminuq256: - case X86::BI__builtin_ia32_pminub512: - case X86::BI__builtin_ia32_pminuw512: - case X86::BI__builtin_ia32_pminud512: - case X86::BI__builtin_ia32_pminuq512: - return EmitX86BinaryIntrinsic(*this, Ops, Intrinsic::umin); case X86::BI__builtin_ia32_pmuludq128: case X86::BI__builtin_ia32_pmuludq256: @@ -14418,12 +14377,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::vector_reduce_add, Ops[0]->getType()); return Builder.CreateCall(F, {Ops[0]}); } - case X86::BI__builtin_ia32_reduce_and_d512: - case X86::BI__builtin_ia32_reduce_and_q512: { - Function *F = - CGM.getIntrinsic(Intrinsic::vector_reduce_and, Ops[0]->getType()); - return Builder.CreateCall(F, {Ops[0]}); - } case X86::BI__builtin_ia32_reduce_fadd_pd512: case X86::BI__builtin_ia32_reduce_fadd_ps512: case X86::BI__builtin_ia32_reduce_fadd_ph512: @@ -14470,36 +14423,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::vector_reduce_mul, Ops[0]->getType()); return Builder.CreateCall(F, {Ops[0]}); } - case X86::BI__builtin_ia32_reduce_or_d512: - case X86::BI__builtin_ia32_reduce_or_q512: { - Function *F = - CGM.getIntrinsic(Intrinsic::vector_reduce_or, Ops[0]->getType()); - return Builder.CreateCall(F, {Ops[0]}); - } - case X86::BI__builtin_ia32_reduce_smax_d512: - case X86::BI__builtin_ia32_reduce_smax_q512: { - Function *F = - CGM.getIntrinsic(Intrinsic::vector_reduce_smax, Ops[0]->getType()); - return Builder.CreateCall(F, {Ops[0]}); - } - case X86::BI__builtin_ia32_reduce_smin_d512: - case X86::BI__builtin_ia32_reduce_smin_q512: { - Function *F = - CGM.getIntrinsic(Intrinsic::vector_reduce_smin, Ops[0]->getType()); - return Builder.CreateCall(F, {Ops[0]}); - } - case X86::BI__builtin_ia32_reduce_umax_d512: - case X86::BI__builtin_ia32_reduce_umax_q512: { - Function *F = - CGM.getIntrinsic(Intrinsic::vector_reduce_umax, Ops[0]->getType()); - return Builder.CreateCall(F, {Ops[0]}); - } - case X86::BI__builtin_ia32_reduce_umin_d512: - case X86::BI__builtin_ia32_reduce_umin_q512: { - Function *F = - CGM.getIntrinsic(Intrinsic::vector_reduce_umin, Ops[0]->getType()); - return Builder.CreateCall(F, {Ops[0]}); - } // 3DNow! case X86::BI__builtin_ia32_pswapdsf: @@ -17279,7 +17202,7 @@ static NVPTXMmaLdstInfo getNVPTXMmaLdstInfo(unsigned BuiltinID) { case NVPTX::BI__mma_tf32_m16n16k8_ld_a: return MMA_LDST(4, m16n16k8_load_a_tf32); case NVPTX::BI__mma_tf32_m16n16k8_ld_b: - return MMA_LDST(2, m16n16k8_load_b_tf32); + return MMA_LDST(4, m16n16k8_load_b_tf32); case NVPTX::BI__mma_tf32_m16n16k8_ld_c: return MMA_LDST(8, m16n16k8_load_c_f32); @@ -18448,15 +18371,11 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, llvm_unreachable("unexpected builtin ID"); } llvm::Type *SrcT = Vec->getType(); - llvm::Type *TruncT = - SrcT->getWithNewType(llvm::IntegerType::get(getLLVMContext(), 32)); + llvm::Type *TruncT = SrcT->getWithNewType(Builder.getInt32Ty()); Function *Callee = CGM.getIntrinsic(IntNo, {TruncT, SrcT}); Value *Trunc = Builder.CreateCall(Callee, Vec); - Value *Splat = Builder.CreateVectorSplat(2, Builder.getInt32(0)); - Value *ConcatMask = - llvm::ConstantVector::get({Builder.getInt32(0), Builder.getInt32(1), - Builder.getInt32(2), Builder.getInt32(3)}); - return Builder.CreateShuffleVector(Trunc, Splat, ConcatMask); + Value *Splat = Constant::getNullValue(TruncT); + return Builder.CreateShuffleVector(Trunc, Splat, ArrayRef<int>{0, 1, 2, 3}); } case WebAssembly::BI__builtin_wasm_shuffle_i8x16: { Value *Ops[18]; @@ -18822,6 +18741,8 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, case RISCV::BI__builtin_riscv_bcompress_64: case RISCV::BI__builtin_riscv_bdecompress_32: case RISCV::BI__builtin_riscv_bdecompress_64: + case RISCV::BI__builtin_riscv_bfp_32: + case RISCV::BI__builtin_riscv_bfp_64: case RISCV::BI__builtin_riscv_grev_32: case RISCV::BI__builtin_riscv_grev_64: case RISCV::BI__builtin_riscv_gorc_32: @@ -18841,7 +18762,11 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, case RISCV::BI__builtin_riscv_crc32c_b: case RISCV::BI__builtin_riscv_crc32c_h: case RISCV::BI__builtin_riscv_crc32c_w: - case RISCV::BI__builtin_riscv_crc32c_d: { + case RISCV::BI__builtin_riscv_crc32c_d: + case RISCV::BI__builtin_riscv_fsl_32: + case RISCV::BI__builtin_riscv_fsr_32: + case RISCV::BI__builtin_riscv_fsl_64: + case RISCV::BI__builtin_riscv_fsr_64: { switch (BuiltinID) { default: llvm_unreachable("unexpected builtin ID"); // Zbb @@ -18871,6 +18796,12 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, ID = Intrinsic::riscv_bdecompress; break; + // Zbf + case RISCV::BI__builtin_riscv_bfp_32: + case RISCV::BI__builtin_riscv_bfp_64: + ID = Intrinsic::riscv_bfp; + break; + // Zbp case RISCV::BI__builtin_riscv_grev_32: case RISCV::BI__builtin_riscv_grev_64: @@ -18926,6 +18857,16 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, case RISCV::BI__builtin_riscv_crc32c_d: ID = Intrinsic::riscv_crc32c_d; break; + + // Zbt + case RISCV::BI__builtin_riscv_fsl_32: + case RISCV::BI__builtin_riscv_fsl_64: + ID = Intrinsic::riscv_fsl; + break; + case RISCV::BI__builtin_riscv_fsr_32: + case RISCV::BI__builtin_riscv_fsr_64: + ID = Intrinsic::riscv_fsr; + break; } IntrinsicTypes = {ResultType}; diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index 9714730e3c4b..0b441e382f11 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -154,6 +154,51 @@ void CGCXXABI::setCXXABIThisValue(CodeGenFunction &CGF, llvm::Value *ThisPtr) { CGF.CXXABIThisValue = ThisPtr; } +bool CGCXXABI::mayNeedDestruction(const VarDecl *VD) const { + if (VD->needsDestruction(getContext())) + return true; + + // If the variable has an incomplete class type (or array thereof), it + // might need destruction. + const Type *T = VD->getType()->getBaseElementTypeUnsafe(); + if (T->getAs<RecordType>() && T->isIncompleteType()) + return true; + + return false; +} + +bool CGCXXABI::isEmittedWithConstantInitializer( + const VarDecl *VD, bool InspectInitForWeakDef) const { + VD = VD->getMostRecentDecl(); + if (VD->hasAttr<ConstInitAttr>()) + return true; + + // All later checks examine the initializer specified on the variable. If + // the variable is weak, such examination would not be correct. + if (!InspectInitForWeakDef && (VD->isWeak() || VD->hasAttr<SelectAnyAttr>())) + return false; + + const VarDecl *InitDecl = VD->getInitializingDeclaration(); + if (!InitDecl) + return false; + + // If there's no initializer to run, this is constant initialization. + if (!InitDecl->hasInit()) + return true; + + // If we have the only definition, we don't need a thread wrapper if we + // will emit the value as a constant. + if (isUniqueGVALinkage(getContext().GetGVALinkageForVariable(VD))) + return !mayNeedDestruction(VD) && InitDecl->evaluateValue(); + + // Otherwise, we need a thread wrapper unless we know that every + // translation unit will emit the value as a constant. We rely on the + // variable being constant-initialized in every translation unit if it's + // constant-initialized in any translation unit, which isn't actually + // guaranteed by the standard but is necessary for sanity. + return InitDecl->hasConstantInitialization(); +} + void CGCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResultType) { assert(!CGF.hasAggregateEvaluationKind(ResultType) && diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index ea839db7528e..b96222b3ce28 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -31,7 +31,6 @@ class CXXConstructorDecl; class CXXDestructorDecl; class CXXMethodDecl; class CXXRecordDecl; -class FieldDecl; class MangleContext; namespace CodeGen { @@ -80,6 +79,18 @@ protected: ASTContext &getContext() const { return CGM.getContext(); } + bool mayNeedDestruction(const VarDecl *VD) const; + + /// Determine whether we will definitely emit this variable with a constant + /// initializer, either because the language semantics demand it or because + /// we know that the initializer is a constant. + // For weak definitions, any initializer available in the current translation + // is not necessarily reflective of the initializer used; such initializers + // are ignored unless if InspectInitForWeakDef is true. + bool + isEmittedWithConstantInitializer(const VarDecl *VD, + bool InspectInitForWeakDef = false) const; + virtual bool requiresArrayCookie(const CXXDeleteExpr *E, QualType eltType); virtual bool requiresArrayCookie(const CXXNewExpr *E); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index d70f78fea6b4..a37ff8844e88 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1892,7 +1892,7 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, } void CodeGenModule::addDefaultFunctionDefinitionAttributes(llvm::Function &F) { - llvm::AttrBuilder FuncAttrs; + llvm::AttrBuilder FuncAttrs(F.getContext()); getDefaultFunctionAttributes(F.getName(), F.hasOptNone(), /* AttrOnCallSite = */ false, FuncAttrs); // TODO: call GetCPUAndFeaturesAttributes? @@ -2014,8 +2014,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, llvm::AttributeList &AttrList, unsigned &CallingConv, bool AttrOnCallSite, bool IsThunk) { - llvm::AttrBuilder FuncAttrs; - llvm::AttrBuilder RetAttrs; + llvm::AttrBuilder FuncAttrs(getLLVMContext()); + llvm::AttrBuilder RetAttrs(getLLVMContext()); // Collect function IR attributes from the CC lowering. // We'll collect the paramete and result attributes later. @@ -2243,7 +2243,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, getLangOpts().Sanitize.has(SanitizerKind::Return); // Determine if the return type could be partially undef - if (CodeGenOpts.EnableNoundefAttrs && HasStrictReturn) { + if (!CodeGenOpts.DisableNoundefAttrs && HasStrictReturn) { if (!RetTy->isVoidType() && RetAI.getKind() != ABIArgInfo::Indirect && DetermineNoUndef(RetTy, getTypes(), DL, RetAI)) RetAttrs.addAttribute(llvm::Attribute::NoUndef); @@ -2302,7 +2302,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, // Attach attributes to sret. if (IRFunctionArgs.hasSRetArg()) { - llvm::AttrBuilder SRETAttrs; + llvm::AttrBuilder SRETAttrs(getLLVMContext()); SRETAttrs.addStructRetAttr(getTypes().ConvertTypeForMem(RetTy)); hasUsedSRet = true; if (RetAI.getInReg()) @@ -2314,7 +2314,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, // Attach attributes to inalloca argument. if (IRFunctionArgs.hasInallocaArg()) { - llvm::AttrBuilder Attrs; + llvm::AttrBuilder Attrs(getLLVMContext()); Attrs.addInAllocaAttr(FI.getArgStruct()); ArgAttrs[IRFunctionArgs.getInallocaArgNo()] = llvm::AttributeSet::get(getLLVMContext(), Attrs); @@ -2329,7 +2329,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, assert(IRArgs.second == 1 && "Expected only a single `this` pointer."); - llvm::AttrBuilder Attrs; + llvm::AttrBuilder Attrs(getLLVMContext()); QualType ThisTy = FI.arg_begin()->type.castAs<PointerType>()->getPointeeType(); @@ -2364,7 +2364,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, I != E; ++I, ++ArgNo) { QualType ParamType = I->type; const ABIArgInfo &AI = I->info; - llvm::AttrBuilder Attrs; + llvm::AttrBuilder Attrs(getLLVMContext()); // Add attribute for padding argument, if necessary. if (IRFunctionArgs.hasPaddingArg(ArgNo)) { @@ -2372,14 +2372,15 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, ArgAttrs[IRFunctionArgs.getPaddingArgNo(ArgNo)] = llvm::AttributeSet::get( getLLVMContext(), - llvm::AttrBuilder().addAttribute(llvm::Attribute::InReg)); + llvm::AttrBuilder(getLLVMContext()).addAttribute(llvm::Attribute::InReg)); } } // Decide whether the argument we're handling could be partially undef - bool ArgNoUndef = DetermineNoUndef(ParamType, getTypes(), DL, AI); - if (CodeGenOpts.EnableNoundefAttrs && ArgNoUndef) + if (!CodeGenOpts.DisableNoundefAttrs && + DetermineNoUndef(ParamType, getTypes(), DL, AI)) { Attrs.addAttribute(llvm::Attribute::NoUndef); + } // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we // have the corresponding parameter variable. It doesn't make @@ -2519,8 +2520,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, unsigned FirstIRArg, NumIRArgs; std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); for (unsigned i = 0; i < NumIRArgs; i++) - ArgAttrs[FirstIRArg + i] = - llvm::AttributeSet::get(getLLVMContext(), Attrs); + ArgAttrs[FirstIRArg + i] = ArgAttrs[FirstIRArg + i].addAttributes( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), Attrs)); } } assert(ArgNo == FI.arg_size()); @@ -2747,11 +2748,11 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, QualType ETy = ArrTy->getElementType(); llvm::Align Alignment = CGM.getNaturalTypeAlignment(ETy).getAsAlign(); - AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(Alignment)); + AI->addAttrs(llvm::AttrBuilder(getLLVMContext()).addAlignmentAttr(Alignment)); uint64_t ArrSize = ArrTy->getSize().getZExtValue(); if (!ETy->isIncompleteType() && ETy->isConstantSizeType() && ArrSize) { - llvm::AttrBuilder Attrs; + llvm::AttrBuilder Attrs(getLLVMContext()); Attrs.addDereferenceableAttr( getContext().getTypeSizeInChars(ETy).getQuantity() * ArrSize); @@ -2771,7 +2772,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, QualType ETy = ArrTy->getElementType(); llvm::Align Alignment = CGM.getNaturalTypeAlignment(ETy).getAsAlign(); - AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(Alignment)); + AI->addAttrs(llvm::AttrBuilder(getLLVMContext()).addAlignmentAttr(Alignment)); if (!getContext().getTargetAddressSpace(ETy) && !CGM.getCodeGenOpts().NullPointerIsValid) AI->addAttr(llvm::Attribute::NonNull); @@ -2793,7 +2794,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, AlignmentCI->getLimitedValue(llvm::Value::MaximumAlignment); if (AI->getParamAlign().valueOrOne() < AlignmentInt) { AI->removeAttr(llvm::Attribute::AttrKind::Alignment); - AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr( + AI->addAttrs(llvm::AttrBuilder(getLLVMContext()).addAlignmentAttr( llvm::Align(AlignmentInt))); } } @@ -3879,9 +3880,8 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, } // Create the temporary. - Address temp = CGF.CreateTempAlloca(destType->getElementType(), - CGF.getPointerAlign(), - "icr.temp"); + Address temp = CGF.CreateTempAlloca(destType->getPointerElementType(), + CGF.getPointerAlign(), "icr.temp"); // Loading an l-value can introduce a cleanup if the l-value is __weak, // and that cleanup will be conditional if we can't prove that the l-value // isn't null, so we need to register a dominating point so that the cleanups @@ -3891,9 +3891,8 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, // Zero-initialize it if we're not doing a copy-initialization. bool shouldCopy = CRE->shouldCopy(); if (!shouldCopy) { - llvm::Value *null = - llvm::ConstantPointerNull::get( - cast<llvm::PointerType>(destType->getElementType())); + llvm::Value *null = llvm::ConstantPointerNull::get( + cast<llvm::PointerType>(destType->getPointerElementType())); CGF.Builder.CreateStore(null, temp); } @@ -3935,7 +3934,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, assert(srcRV.isScalar()); llvm::Value *src = srcRV.getScalarVal(); - src = CGF.Builder.CreateBitCast(src, destType->getElementType(), + src = CGF.Builder.CreateBitCast(src, destType->getPointerElementType(), "icr.cast"); // Use an ordinary store, not a store-to-lvalue. @@ -5074,8 +5073,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, #ifndef NDEBUG // Assert that these structs have equivalent element types. llvm::StructType *FullTy = CallInfo.getArgStruct(); - llvm::StructType *DeclaredTy = cast<llvm::StructType>( - cast<llvm::PointerType>(LastParamTy)->getElementType()); + llvm::StructType *DeclaredTy = + cast<llvm::StructType>(LastParamTy->getPointerElementType()); assert(DeclaredTy->getNumElements() == FullTy->getNumElements()); for (llvm::StructType::element_iterator DI = DeclaredTy->element_begin(), DE = DeclaredTy->element_end(), diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index c8594068c3fc..af63e1bddd2d 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -26,17 +26,13 @@ #include "ABIInfo.h" namespace llvm { -class AttributeList; -class Function; class Type; class Value; } // namespace llvm namespace clang { -class ASTContext; class Decl; class FunctionDecl; -class ObjCMethodDecl; class VarDecl; namespace CodeGen { @@ -49,11 +45,11 @@ class CGCalleeInfo { GlobalDecl CalleeDecl; public: - explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl() {} + explicit CGCalleeInfo() : CalleeProtoTy(nullptr) {} CGCalleeInfo(const FunctionProtoType *calleeProtoTy, GlobalDecl calleeDecl) : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {} CGCalleeInfo(const FunctionProtoType *calleeProtoTy) - : CalleeProtoTy(calleeProtoTy), CalleeDecl() {} + : CalleeProtoTy(calleeProtoTy) {} CGCalleeInfo(GlobalDecl calleeDecl) : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {} @@ -116,7 +112,8 @@ public: assert(functionPtr && "configuring callee without function pointer"); assert(functionPtr->getType()->isPointerTy()); assert(functionPtr->getType()->isOpaquePointerTy() || - functionPtr->getType()->getPointerElementType()->isFunctionTy()); + functionPtr->getType()->getNonOpaquePointerElementType() + ->isFunctionTy()); } static CGCallee forBuiltin(unsigned builtinID, diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 8f99ff0d50ff..520e119ada26 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -390,7 +390,7 @@ Address CodeGenFunction::GetAddressOfBaseClass( llvm::PHINode *PHI = Builder.CreatePHI(BasePtrTy, 2, "cast.result"); PHI->addIncoming(Value.getPointer(), notNullBB); PHI->addIncoming(llvm::Constant::getNullValue(BasePtrTy), origBB); - Value = Address(PHI, Value.getAlignment()); + Value = Value.withPointer(PHI); } return Value; @@ -1983,7 +1983,7 @@ void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, CharUnits eltAlignment = arrayBase.getAlignment() .alignmentOfArrayElement(getContext().getTypeSizeInChars(type)); - Address curAddr = Address(cur, eltAlignment); + Address curAddr = Address(cur, elementType, eltAlignment); // Zero initialize the storage, if requested. if (zeroInitialize) @@ -2852,9 +2852,8 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad( SanitizerHandler::CFICheckFail, {}, {}); } - return Builder.CreateBitCast( - Builder.CreateExtractValue(CheckedLoad, 0), - cast<llvm::PointerType>(VTable->getType())->getElementType()); + return Builder.CreateBitCast(Builder.CreateExtractValue(CheckedLoad, 0), + VTable->getType()->getPointerElementType()); } void CodeGenFunction::EmitForwardingCallToLambda( diff --git a/clang/lib/CodeGen/CGCleanup.h b/clang/lib/CodeGen/CGCleanup.h index 76f3a48f32f3..079a3e25d6dc 100644 --- a/clang/lib/CodeGen/CGCleanup.h +++ b/clang/lib/CodeGen/CGCleanup.h @@ -23,7 +23,6 @@ namespace llvm { class BasicBlock; class Value; class ConstantInt; -class AllocaInst; } namespace clang { diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp index 2041d2a5b4c9..c1763cbbc5a0 100644 --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -707,6 +707,10 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { if (Stmt *Ret = S.getReturnStmt()) EmitStmt(Ret); + + // LLVM require the frontend to add the function attribute. See + // Coroutines.rst. + CurFn->addFnAttr("coroutine.presplit", "0"); } // Emit coroutine intrinsic and patch up arguments of the token type. diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 6e189a61dd20..1a9080604a79 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -354,13 +354,9 @@ CGDebugInfo::computeChecksum(FileID FID, SmallString<32> &Checksum) const { if (!MemBuffer) return None; - llvm::MD5 Hash; - llvm::MD5::MD5Result Result; - - Hash.update(MemBuffer->getBuffer()); - Hash.final(Result); - - Hash.stringifyResult(Result, Checksum); + llvm::toHex( + llvm::MD5::hash(llvm::arrayRefFromStringRef(MemBuffer->getBuffer())), + /*LowerCase*/ true, Checksum); return llvm::DIFile::CSK_MD5; } @@ -722,7 +718,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { auto *LowerBound = llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0)); - SmallVector<int64_t, 9> Expr( + SmallVector<uint64_t, 9> Expr( {llvm::dwarf::DW_OP_constu, NumElemsPerVG, llvm::dwarf::DW_OP_bregx, /* AArch64::VG */ 46, 0, llvm::dwarf::DW_OP_mul, llvm::dwarf::DW_OP_constu, 1, llvm::dwarf::DW_OP_minus}); @@ -768,7 +764,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { } // Element count = (VLENB / SEW) x LMUL - SmallVector<int64_t, 12> Expr( + SmallVector<uint64_t, 12> Expr( // The DW_OP_bregx operation has two operands: a register which is // specified by an unsigned LEB128 number, followed by a signed LEB128 // offset. @@ -3690,7 +3686,7 @@ void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD, const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) { // Seek non-virtual primary base root. - while (1) { + while (true) { const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase); const CXXRecordDecl *PBT = BRL.getPrimaryBase(); if (PBT && !BRL.isPrimaryBaseVirtual()) @@ -4325,7 +4321,7 @@ void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { } void CGDebugInfo::AppendAddressSpaceXDeref( - unsigned AddressSpace, SmallVectorImpl<int64_t> &Expr) const { + unsigned AddressSpace, SmallVectorImpl<uint64_t> &Expr) const { Optional<unsigned> DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(AddressSpace); if (!DWARFAddressSpace) @@ -4494,7 +4490,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, Line = getLineNumber(VD->getLocation()); Column = getColumnNumber(VD->getLocation()); } - SmallVector<int64_t, 13> Expr; + SmallVector<uint64_t, 13> Expr; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (VD->isImplicit()) Flags |= llvm::DINode::FlagArtificial; @@ -4720,7 +4716,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( target.getStructLayout(blockInfo.StructureType) ->getElementOffset(blockInfo.getCapture(VD).getIndex())); - SmallVector<int64_t, 9> addr; + SmallVector<uint64_t, 9> addr; addr.push_back(llvm::dwarf::DW_OP_deref); addr.push_back(llvm::dwarf::DW_OP_plus_uconst); addr.push_back(offset.getQuantity()); @@ -5191,7 +5187,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, } else { auto Align = getDeclAlignIfRequired(D, CGM.getContext()); - SmallVector<int64_t, 4> Expr; + SmallVector<uint64_t, 4> Expr; unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(D->getType()); if (CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 14ff0eeabd21..a76426e585c8 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -40,7 +40,6 @@ class ClassTemplateSpecializationDecl; class GlobalDecl; class ModuleMap; class ObjCInterfaceDecl; -class ObjCIvarDecl; class UsingDecl; class VarDecl; enum class DynamicInitKind : unsigned; @@ -363,7 +362,7 @@ class CGDebugInfo { /// Extended dereferencing mechanism is has the following format: /// DW_OP_constu <DWARF Address Space> DW_OP_swap DW_OP_xderef void AppendAddressSpaceXDeref(unsigned AddressSpace, - SmallVectorImpl<int64_t> &Expr) const; + SmallVectorImpl<uint64_t> &Expr) const; /// A helper function to collect debug info for the default elements of a /// block. diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index e09279c1d455..18d658436086 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1392,9 +1392,11 @@ void CodeGenFunction::EmitAndRegisterVariableArrayDimensions( else { // Create an artificial VarDecl to generate debug info for. IdentifierInfo *NameIdent = VLAExprNames[NameIdx++]; - auto VlaExprTy = VlaSize.NumElts->getType()->getPointerElementType(); + assert(cast<llvm::PointerType>(VlaSize.NumElts->getType()) + ->isOpaqueOrPointeeTypeMatches(SizeTy) && + "Number of VLA elements must be SizeTy"); auto QT = getContext().getIntTypeForBitwidth( - VlaExprTy->getScalarSizeInBits(), false); + SizeTy->getScalarSizeInBits(), false); auto *ArtificialDecl = VarDecl::Create( getContext(), const_cast<DeclContext *>(D.getDeclContext()), D.getLocation(), D.getLocation(), NameIdent, QT, @@ -2250,16 +2252,17 @@ void CodeGenFunction::emitArrayDestroy(llvm::Value *begin, // Shift the address back by one element. llvm::Value *negativeOne = llvm::ConstantInt::get(SizeTy, -1, true); + llvm::Type *llvmElementType = ConvertTypeForMem(elementType); llvm::Value *element = Builder.CreateInBoundsGEP( - elementPast->getType()->getPointerElementType(), elementPast, negativeOne, - "arraydestroy.element"); + llvmElementType, elementPast, negativeOne, "arraydestroy.element"); if (useEHCleanup) pushRegularPartialArrayCleanup(begin, element, elementType, elementAlign, destroyer); // Perform the actual destruction there. - destroyer(*this, Address(element, elementAlign), elementType); + destroyer(*this, Address(element, llvmElementType, elementAlign), + elementType); if (useEHCleanup) PopCleanupBlock(); diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 3579761f1429..7b880c1354e1 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -136,6 +136,7 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, } // Otherwise, the standard logic requires a helper function. } else { + Addr = Addr.getElementBitCast(CGF.ConvertTypeForMem(Type)); Func = CodeGenFunction(CGM) .generateDestroyHelper(Addr, Type, CGF.getDestroyer(DtorKind), CGF.needsEHCleanup(DtorKind), &D); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 34b4951a7f72..0fb7ec26a85e 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1931,7 +1931,7 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { if (LV.isMatrixElt()) { llvm::Value *Idx = LV.getMatrixIdx(); if (CGM.getCodeGenOpts().OptimizationLevel > 0) { - const auto *const MatTy = LV.getType()->getAs<ConstantMatrixType>(); + const auto *const MatTy = LV.getType()->castAs<ConstantMatrixType>(); llvm::MatrixBuilder<CGBuilderTy> MB(Builder); MB.CreateIndexAssumption(Idx, MatTy->getNumElementsFlattened()); } @@ -2077,7 +2077,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, if (Dst.isMatrixElt()) { llvm::Value *Idx = Dst.getMatrixIdx(); if (CGM.getCodeGenOpts().OptimizationLevel > 0) { - const auto *const MatTy = Dst.getType()->getAs<ConstantMatrixType>(); + const auto *const MatTy = Dst.getType()->castAs<ConstantMatrixType>(); llvm::MatrixBuilder<CGBuilderTy> MB(Builder); MB.CreateIndexAssumption(Idx, MatTy->getNumElementsFlattened()); } @@ -3178,7 +3178,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF, bool MayReturn = !IsFatal || RecoverKind == CheckRecoverableKind::AlwaysRecoverable; - llvm::AttrBuilder B; + llvm::AttrBuilder B(CGF.getLLVMContext()); if (!MayReturn) { B.addAttribute(llvm::Attribute::NoReturn) .addAttribute(llvm::Attribute::NoUnwind); @@ -4699,12 +4699,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { if (LV.isSimple()) { Address V = LV.getAddress(*this); if (V.isValid()) { - llvm::Type *T = - ConvertTypeForMem(E->getType()) - ->getPointerTo( - cast<llvm::PointerType>(V.getType())->getAddressSpace()); - if (V.getType() != T) - LV.setAddress(Builder.CreateBitCast(V, T)); + llvm::Type *T = ConvertTypeForMem(E->getType()); + if (V.getElementType() != T) + LV.setAddress(Builder.CreateElementBitCast(V, T)); } } return LV; @@ -4763,8 +4760,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { CGM.EmitExplicitCastExprType(CE, this); LValue LV = EmitLValue(E->getSubExpr()); - Address V = Builder.CreateBitCast(LV.getAddress(*this), - ConvertType(CE->getTypeAsWritten())); + Address V = Builder.CreateElementBitCast( + LV.getAddress(*this), + ConvertTypeForMem(CE->getTypeAsWritten()->getPointeeType())); if (SanOpts.has(SanitizerKind::CFIUnrelatedCast)) EmitVTablePtrCheckForCast(E->getType(), V.getPointer(), diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 3b996b89a1d7..0968afd82064 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -614,8 +614,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, // every temporary created in a default argument is sequenced before // the construction of the next array element, if any CodeGenFunction::RunCleanupsScope CleanupsScope(CGF); - LValue elementLV = - CGF.MakeAddrLValue(Address(currentElement, elementAlign), elementType); + LValue elementLV = CGF.MakeAddrLValue( + Address(currentElement, llvmElementType, elementAlign), elementType); if (filler) EmitInitializationToLValue(filler, elementLV); else @@ -1801,6 +1801,7 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E, CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType); CharUnits elementAlign = destPtr.getAlignment().alignmentOfArrayElement(elementSize); + llvm::Type *llvmElementType = CGF.ConvertTypeForMem(elementType); llvm::BasicBlock *entryBB = Builder.GetInsertBlock(); llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body"); @@ -1810,8 +1811,8 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E, llvm::PHINode *index = Builder.CreatePHI(zero->getType(), 2, "arrayinit.index"); index->addIncoming(zero, entryBB); - llvm::Value *element = Builder.CreateInBoundsGEP( - begin->getType()->getPointerElementType(), begin, index); + llvm::Value *element = + Builder.CreateInBoundsGEP(llvmElementType, begin, index); // Prepare for a cleanup. QualType::DestructionKind dtorKind = elementType.isDestructedType(); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index e32462eb635c..4e8933fffe03 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1613,8 +1613,9 @@ ScalarExprEmitter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) { if (GlobalConstStr->getType()->getPointerAddressSpace() == ExprAS) return GlobalConstStr; - llvm::Type *EltTy = GlobalConstStr->getType()->getPointerElementType(); - llvm::PointerType *NewPtrTy = llvm::PointerType::get(EltTy, ExprAS); + llvm::PointerType *PtrTy = cast<llvm::PointerType>(GlobalConstStr->getType()); + llvm::PointerType *NewPtrTy = + llvm::PointerType::getWithSamePointeeType(PtrTy, ExprAS); return Builder.CreateAddrSpaceCast(GlobalConstStr, NewPtrTy, "usn_addr_cast"); } diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index b5bcf157036d..8cc609186f9e 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -847,7 +847,7 @@ static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar, static bool hasUnalignedAtomics(llvm::Triple::ArchType arch) { // FIXME: Allow unaligned atomic load/store on x86. (It is not // currently supported by the backend.) - return 0; + return false; } /// Return the maximum size that permits atomic accesses for the given diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index b2bf60d2c0fc..52b449090868 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -2347,9 +2347,10 @@ llvm::Value *CGObjCGNU::GetTypedSelector(CodeGenFunction &CGF, Selector Sel, } } if (!SelValue) { - SelValue = llvm::GlobalAlias::create( - SelectorTy->getElementType(), 0, llvm::GlobalValue::PrivateLinkage, - ".objc_selector_" + Sel.getAsString(), &TheModule); + SelValue = llvm::GlobalAlias::create(SelectorTy->getPointerElementType(), 0, + llvm::GlobalValue::PrivateLinkage, + ".objc_selector_" + Sel.getAsString(), + &TheModule); Types.emplace_back(TypeEncoding, SelValue); } @@ -2576,14 +2577,16 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, if (IsClassMessage) { if (!MetaClassPtrAlias) { MetaClassPtrAlias = llvm::GlobalAlias::create( - IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage, + IdTy->getPointerElementType(), 0, + llvm::GlobalValue::InternalLinkage, ".objc_metaclass_ref" + Class->getNameAsString(), &TheModule); } ReceiverClass = MetaClassPtrAlias; } else { if (!ClassPtrAlias) { ClassPtrAlias = llvm::GlobalAlias::create( - IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage, + IdTy->getPointerElementType(), 0, + llvm::GlobalValue::InternalLinkage, ".objc_class_ref" + Class->getNameAsString(), &TheModule); } ReceiverClass = ClassPtrAlias; @@ -3706,7 +3709,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { GenerateProtocolHolderCategory(); llvm::StructType *selStructTy = - dyn_cast<llvm::StructType>(SelectorTy->getElementType()); + dyn_cast<llvm::StructType>(SelectorTy->getPointerElementType()); llvm::Type *selStructPtrTy = SelectorTy; if (!selStructTy) { selStructTy = llvm::StructType::get(CGM.getLLVMContext(), diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 425d1a793439..e7dba4c8feab 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -2138,16 +2138,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCCommonTypesHelper &ObjCTypes) { CodeGenTypes &Types = CGM.getTypes(); auto selTy = CGF.getContext().getObjCSelType(); - llvm::Value *SelValue; - - if (Method && Method->isDirectMethod()) { - // Direct methods will synthesize the proper `_cmd` internally, - // so just don't bother with setting the `_cmd` argument. - assert(!IsSuper); - SelValue = llvm::UndefValue::get(Types.ConvertType(selTy)); - } else { - SelValue = GetSelector(CGF, Sel); - } + llvm::Value *SelValue = llvm::UndefValue::get(Types.ConvertType(selTy)); CallArgList ActualArgs; if (!IsSuper) @@ -2168,10 +2159,15 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, canMessageReceiverBeNull(CGF, Method, IsSuper, ClassReceiver, Arg0); bool RequiresNullCheck = false; + bool RequiresSelValue = true; llvm::FunctionCallee Fn = nullptr; if (Method && Method->isDirectMethod()) { + assert(!IsSuper); Fn = GenerateDirectMethod(Method, Method->getClassInterface()); + // Direct methods will synthesize the proper `_cmd` internally, + // so just don't bother with setting the `_cmd` argument. + RequiresSelValue = false; } else if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) { if (ReceiverCanBeNull) RequiresNullCheck = true; Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper) @@ -2209,6 +2205,12 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, nullReturn.init(CGF, Arg0); } + // If a selector value needs to be passed, emit the load before the call. + if (RequiresSelValue) { + SelValue = GetSelector(CGF, Sel); + ActualArgs[1] = CallArg(RValue::get(SelValue), selTy); + } + llvm::CallBase *CallSite; CGCallee Callee = CGCallee::forDirect(BitcastFn); RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs, @@ -2487,7 +2489,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, if (FQT->isUnionType()) HasUnion = true; - BuildRCBlockVarRecordLayout(FQT->getAs<RecordType>(), + BuildRCBlockVarRecordLayout(FQT->castAs<RecordType>(), BytePos + FieldOffset, HasUnion); continue; } @@ -2935,8 +2937,7 @@ CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, std::string CGObjCCommonMac::getRCBlockLayoutStr(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { fillRunSkipBlockVars(CGM, blockInfo); - return getBlockLayoutInfoString(RunSkipBlockVars, - blockInfo.needsCopyDisposeHelpers()); + return getBlockLayoutInfoString(RunSkipBlockVars, blockInfo.NeedsCopyDispose); } llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM, @@ -4370,7 +4371,11 @@ FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) { void FragileHazards::emitWriteHazard() { if (Locals.empty()) return; - CGF.EmitNounwindRuntimeCall(WriteHazard, Locals); + llvm::CallInst *Call = CGF.EmitNounwindRuntimeCall(WriteHazard, Locals); + for (auto Pair : llvm::enumerate(Locals)) + Call->addParamAttr(Pair.index(), llvm::Attribute::get( + CGF.getLLVMContext(), llvm::Attribute::ElementType, + cast<llvm::AllocaInst>(Pair.value())->getAllocatedType())); } void FragileHazards::emitReadHazard(CGBuilderTy &Builder) { @@ -4378,6 +4383,10 @@ void FragileHazards::emitReadHazard(CGBuilderTy &Builder) { llvm::CallInst *call = Builder.CreateCall(ReadHazard, Locals); call->setDoesNotThrow(); call->setCallingConv(CGF.getRuntimeCC()); + for (auto Pair : llvm::enumerate(Locals)) + call->addParamAttr(Pair.index(), llvm::Attribute::get( + Builder.getContext(), llvm::Attribute::ElementType, + cast<llvm::AllocaInst>(Pair.value())->getAllocatedType())); } /// Emit read hazards in all the protected blocks, i.e. all the blocks diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index e35c15421520..db1c3ca191ca 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -837,12 +837,11 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) { } llvm::Value *Size; llvm::Value *SizeInChars; - auto *ElemType = - cast<llvm::PointerType>(OrigAddresses[N].first.getPointer(CGF)->getType()) - ->getElementType(); + auto *ElemType = OrigAddresses[N].first.getAddress(CGF).getElementType(); auto *ElemSizeOf = llvm::ConstantExpr::getSizeOf(ElemType); if (AsArraySection) { - Size = CGF.Builder.CreatePtrDiff(OrigAddresses[N].second.getPointer(CGF), + Size = CGF.Builder.CreatePtrDiff(ElemType, + OrigAddresses[N].second.getPointer(CGF), OrigAddresses[N].first.getPointer(CGF)); Size = CGF.Builder.CreateNUWAdd( Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1)); @@ -1008,7 +1007,8 @@ Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N, OriginalBaseLValue); Address SharedAddr = SharedAddresses[N].first.getAddress(CGF); llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff( - BaseLValue.getPointer(CGF), SharedAddr.getPointer()); + SharedAddr.getElementType(), BaseLValue.getPointer(CGF), + SharedAddr.getPointer()); llvm::Value *PrivatePointer = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( PrivateAddr.getPointer(), SharedAddr.getType()); @@ -1429,24 +1429,25 @@ static StringRef getIdentStringFromSourceLocation(CodeGenFunction &CGF, llvm::Value *CGOpenMPRuntime::emitUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc, unsigned Flags) { + uint32_t SrcLocStrSize; llvm::Constant *SrcLocStr; if (CGM.getCodeGenOpts().getDebugInfo() == codegenoptions::NoDebugInfo || Loc.isInvalid()) { - SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr(); + SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize); } else { - std::string FunctionName = ""; + std::string FunctionName; if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl)) FunctionName = FD->getQualifiedNameAsString(); PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc); const char *FileName = PLoc.getFilename(); unsigned Line = PLoc.getLine(); unsigned Column = PLoc.getColumn(); - SrcLocStr = - OMPBuilder.getOrCreateSrcLocStr(FunctionName, FileName, Line, Column); + SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(FunctionName, FileName, Line, + Column, SrcLocStrSize); } unsigned Reserved2Flags = getDefaultLocationReserved2Flags(); - return OMPBuilder.getOrCreateIdent(SrcLocStr, llvm::omp::IdentFlag(Flags), - Reserved2Flags); + return OMPBuilder.getOrCreateIdent( + SrcLocStr, SrcLocStrSize, llvm::omp::IdentFlag(Flags), Reserved2Flags); } llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF, @@ -1457,10 +1458,11 @@ llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF, if (CGM.getLangOpts().OpenMPIRBuilder) { SmallString<128> Buffer; OMPBuilder.updateToLocation(CGF.Builder.saveIP()); + uint32_t SrcLocStrSize; auto *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr( - getIdentStringFromSourceLocation(CGF, Loc, Buffer)); + getIdentStringFromSourceLocation(CGF, Loc, Buffer), SrcLocStrSize); return OMPBuilder.getOrCreateThreadID( - OMPBuilder.getOrCreateIdent(SrcLocStr)); + OMPBuilder.getOrCreateIdent(SrcLocStr, SrcLocStrSize)); } llvm::Value *ThreadID = nullptr; @@ -3464,8 +3466,7 @@ static bool isAllocatableDecl(const VarDecl *VD) { return false; const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>(); // Use the default allocation. - return !((AA->getAllocatorType() == OMPAllocateDeclAttr::OMPDefaultMemAlloc || - AA->getAllocatorType() == OMPAllocateDeclAttr::OMPNullMemAlloc) && + return !(AA->getAllocatorType() == OMPAllocateDeclAttr::OMPDefaultMemAlloc && !AA->getAllocator()); } @@ -8120,7 +8121,7 @@ private: .getAddress(CGF); } Size = CGF.Builder.CreatePtrDiff( - CGF.EmitCastToVoidPtr(ComponentLB.getPointer()), + CGF.Int8Ty, CGF.EmitCastToVoidPtr(ComponentLB.getPointer()), CGF.EmitCastToVoidPtr(LB.getPointer())); break; } @@ -8141,7 +8142,7 @@ private: CombinedInfo.BasePointers.push_back(BP.getPointer()); CombinedInfo.Pointers.push_back(LB.getPointer()); Size = CGF.Builder.CreatePtrDiff( - CGF.Builder.CreateConstGEP(HB, 1).getPointer(), + CGF.Int8Ty, CGF.Builder.CreateConstGEP(HB, 1).getPointer(), CGF.EmitCastToVoidPtr(LB.getPointer())); CombinedInfo.Sizes.push_back( CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/true)); @@ -8967,7 +8968,7 @@ public: CGF.Builder.CreateConstGEP1_32(HBAddr.getElementType(), HB, /*Idx0=*/1); llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy); llvm::Value *CHAddr = CGF.Builder.CreatePointerCast(HAddr, CGF.VoidPtrTy); - llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CHAddr, CLAddr); + llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CGF.Int8Ty, CHAddr, CLAddr); llvm::Value *Size = CGF.Builder.CreateIntCast(Diff, CGF.Int64Ty, /*isSigned=*/false); CombinedInfo.Sizes.push_back(Size); @@ -9527,8 +9528,9 @@ llvm::Constant * emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder, MappableExprsHandler::MappingExprInfo &MapExprs) { + uint32_t SrcLocStrSize; if (!MapExprs.getMapDecl() && !MapExprs.getMapExpr()) - return OMPBuilder.getOrCreateDefaultSrcLocStr(); + return OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize); SourceLocation Loc; if (!MapExprs.getMapDecl() && MapExprs.getMapExpr()) { @@ -9540,7 +9542,7 @@ emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder, Loc = MapExprs.getMapDecl()->getLocation(); } - std::string ExprName = ""; + std::string ExprName; if (MapExprs.getMapExpr()) { PrintingPolicy P(CGF.getContext().getLangOpts()); llvm::raw_string_ostream OS(ExprName); @@ -9551,8 +9553,9 @@ emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder, } PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc); - return OMPBuilder.getOrCreateSrcLocStr(PLoc.getFilename(), ExprName.c_str(), - PLoc.getLine(), PLoc.getColumn()); + return OMPBuilder.getOrCreateSrcLocStr(PLoc.getFilename(), ExprName, + PLoc.getLine(), PLoc.getColumn(), + SrcLocStrSize); } /// Emit the arrays used to pass the captures and map information to the @@ -10216,8 +10219,7 @@ void CGOpenMPRuntime::emitUDMapperArrayInitOrDel( llvm::Value *Cond; if (IsInit) { // base != begin? - llvm::Value *BaseIsBegin = MapperCGF.Builder.CreateIsNotNull( - MapperCGF.Builder.CreatePtrDiff(Base, Begin)); + llvm::Value *BaseIsBegin = MapperCGF.Builder.CreateICmpNE(Base, Begin); // IsPtrAndObj? llvm::Value *PtrAndObjBit = MapperCGF.Builder.CreateAnd( MapType, @@ -10581,7 +10583,7 @@ void CGOpenMPRuntime::emitTargetCall( emitOffloadingArraysArgument( CGF, Info.BasePointersArray, Info.PointersArray, Info.SizesArray, Info.MapTypesArray, Info.MapNamesArray, Info.MappersArray, Info, - {/*ForEndTask=*/false}); + {/*ForEndCall=*/false}); InputInfo.NumberOfTargetItems = Info.NumberOfPtrs; InputInfo.BasePointersArray = @@ -11463,7 +11465,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( emitOffloadingArraysArgument( CGF, Info.BasePointersArray, Info.PointersArray, Info.SizesArray, Info.MapTypesArray, Info.MapNamesArray, Info.MappersArray, Info, - {/*ForEndTask=*/false}); + {/*ForEndCall=*/false}); InputInfo.NumberOfTargetItems = Info.NumberOfPtrs; InputInfo.BasePointersArray = Address(Info.BasePointersArray, CGM.getPointerAlign()); @@ -12213,6 +12215,26 @@ Address CGOpenMPRuntime::getParameterAddress(CodeGenFunction &CGF, return CGF.GetAddrOfLocalVar(NativeParam); } +/// Return allocator value from expression, or return a null allocator (default +/// when no allocator specified). +static llvm::Value *getAllocatorVal(CodeGenFunction &CGF, + const Expr *Allocator) { + llvm::Value *AllocVal; + if (Allocator) { + AllocVal = CGF.EmitScalarExpr(Allocator); + // According to the standard, the original allocator type is a enum + // (integer). Convert to pointer type, if required. + AllocVal = CGF.EmitScalarConversion(AllocVal, Allocator->getType(), + CGF.getContext().VoidPtrTy, + Allocator->getExprLoc()); + } else { + // If no allocator specified, it defaults to the null allocator. + AllocVal = llvm::Constant::getNullValue( + CGF.CGM.getTypes().ConvertType(CGF.getContext().VoidPtrTy)); + } + return AllocVal; +} + Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, const VarDecl *VD) { if (!VD) @@ -12249,20 +12271,24 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, } llvm::Value *ThreadID = getThreadID(CGF, CVD->getBeginLoc()); const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>(); - assert(AA->getAllocator() && - "Expected allocator expression for non-default allocator."); - llvm::Value *Allocator = CGF.EmitScalarExpr(AA->getAllocator()); - // According to the standard, the original allocator type is a enum - // (integer). Convert to pointer type, if required. - Allocator = CGF.EmitScalarConversion( - Allocator, AA->getAllocator()->getType(), CGF.getContext().VoidPtrTy, - AA->getAllocator()->getExprLoc()); - llvm::Value *Args[] = {ThreadID, Size, Allocator}; - - llvm::Value *Addr = - CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( - CGM.getModule(), OMPRTL___kmpc_alloc), - Args, getName({CVD->getName(), ".void.addr"})); + const Expr *Allocator = AA->getAllocator(); + llvm::Value *AllocVal = getAllocatorVal(CGF, Allocator); + llvm::Value *Alignment = + AA->getAlignment() + ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(AA->getAlignment()), + CGM.SizeTy, /*isSigned=*/false) + : nullptr; + SmallVector<llvm::Value *, 4> Args; + Args.push_back(ThreadID); + if (Alignment) + Args.push_back(Alignment); + Args.push_back(Size); + Args.push_back(AllocVal); + llvm::omp::RuntimeFunction FnID = + Alignment ? OMPRTL___kmpc_aligned_alloc : OMPRTL___kmpc_alloc; + llvm::Value *Addr = CGF.EmitRuntimeCall( + OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), FnID), Args, + getName({CVD->getName(), ".void.addr"})); llvm::FunctionCallee FiniRTLFn = OMPBuilder.getOrCreateRuntimeFunction( CGM.getModule(), OMPRTL___kmpc_free); QualType Ty = CGM.getContext().getPointerType(CVD->getType()); @@ -12276,14 +12302,14 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, llvm::FunctionCallee RTLFn; SourceLocation::UIntTy LocEncoding; Address Addr; - const Expr *Allocator; + const Expr *AllocExpr; public: OMPAllocateCleanupTy(llvm::FunctionCallee RTLFn, SourceLocation::UIntTy LocEncoding, Address Addr, - const Expr *Allocator) + const Expr *AllocExpr) : RTLFn(RTLFn), LocEncoding(LocEncoding), Addr(Addr), - Allocator(Allocator) {} + AllocExpr(AllocExpr) {} void Emit(CodeGenFunction &CGF, Flags /*flags*/) override { if (!CGF.HaveInsertPoint()) return; @@ -12292,14 +12318,8 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, CGF, SourceLocation::getFromRawEncoding(LocEncoding)); Args[1] = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( Addr.getPointer(), CGF.VoidPtrTy); - llvm::Value *AllocVal = CGF.EmitScalarExpr(Allocator); - // According to the standard, the original allocator type is a enum - // (integer). Convert to pointer type, if required. - AllocVal = CGF.EmitScalarConversion(AllocVal, Allocator->getType(), - CGF.getContext().VoidPtrTy, - Allocator->getExprLoc()); + llvm::Value *AllocVal = getAllocatorVal(CGF, AllocExpr); Args[2] = AllocVal; - CGF.EmitRuntimeCall(RTLFn, Args); } }; @@ -12307,7 +12327,7 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, UntiedRealAddr.isValid() ? UntiedRealAddr : Address(Addr, Align); CGF.EHStack.pushCleanup<OMPAllocateCleanupTy>( NormalAndEHCleanup, FiniRTLFn, CVD->getLocation().getRawEncoding(), - VDAddr, AA->getAllocator()); + VDAddr, Allocator); if (UntiedRealAddr.isValid()) if (auto *Region = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index b83ec78696d1..19754b0cfacc 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -35,7 +35,6 @@ class ArrayType; class Constant; class FunctionType; class GlobalVariable; -class StructType; class Type; class Value; class OpenMPIRBuilder; @@ -48,7 +47,6 @@ class OMPExecutableDirective; class OMPLoopDirective; class VarDecl; class OMPDeclareReductionDecl; -class IdentifierInfo; namespace CodeGen { class Address; diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 866454ddeaed..e09ea5e01b1a 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -1402,10 +1402,14 @@ void CGOpenMPRuntimeGPU::emitGenericVarsProlog(CodeGenFunction &CGF, // Allocate space for the variable to be globalized llvm::Value *AllocArgs[] = {CGF.getTypeSize(VD->getType())}; - llvm::Instruction *VoidPtr = + llvm::CallBase *VoidPtr = CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( CGM.getModule(), OMPRTL___kmpc_alloc_shared), AllocArgs, VD->getName()); + // FIXME: We should use the variables actual alignment as an argument. + VoidPtr->addRetAttr(llvm::Attribute::get( + CGM.getLLVMContext(), llvm::Attribute::Alignment, + CGM.getContext().getTargetInfo().getNewAlign() / 8)); // Cast the void pointer and get the address of the globalized variable. llvm::PointerType *VarPtrTy = CGF.ConvertTypeForMem(VarTy)->getPointerTo(); @@ -1438,10 +1442,13 @@ void CGOpenMPRuntimeGPU::emitGenericVarsProlog(CodeGenFunction &CGF, // Allocate space for this VLA object to be globalized. llvm::Value *AllocArgs[] = {CGF.getTypeSize(VD->getType())}; - llvm::Instruction *VoidPtr = + llvm::CallBase *VoidPtr = CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( CGM.getModule(), OMPRTL___kmpc_alloc_shared), AllocArgs, VD->getName()); + VoidPtr->addRetAttr( + llvm::Attribute::get(CGM.getLLVMContext(), llvm::Attribute::Alignment, + CGM.getContext().getTargetInfo().getNewAlign())); I->getSecond().EscapedVariableLengthDeclsAddrs.emplace_back( std::pair<llvm::Value *, llvm::Value *>( @@ -1791,8 +1798,9 @@ static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr, Ptr = Address(PhiSrc, Ptr.getAlignment()); ElemPtr = Address(PhiDest, ElemPtr.getAlignment()); llvm::Value *PtrDiff = Bld.CreatePtrDiff( - PtrEnd.getPointer(), Bld.CreatePointerBitCastOrAddrSpaceCast( - Ptr.getPointer(), CGF.VoidPtrTy)); + CGF.Int8Ty, PtrEnd.getPointer(), + Bld.CreatePointerBitCastOrAddrSpaceCast(Ptr.getPointer(), + CGF.VoidPtrTy)); Bld.CreateCondBr(Bld.CreateICmpSGT(PtrDiff, Bld.getInt64(IntSize - 1)), ThenBB, ExitBB); CGF.EmitBlock(ThenBB); @@ -3394,12 +3402,13 @@ CGOpenMPRuntimeGPU::getParameterAddress(CodeGenFunction &CGF, LocalAddr, /*Volatile=*/false, TargetTy, SourceLocation()); // First cast to generic. TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo( - /*AddrSpace=*/0)); + TargetAddr, llvm::PointerType::getWithSamePointeeType( + cast<llvm::PointerType>(TargetAddr->getType()), /*AddrSpace=*/0)); // Cast from generic to native address space. TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo( - NativePointeeAddrSpace)); + TargetAddr, llvm::PointerType::getWithSamePointeeType( + cast<llvm::PointerType>(TargetAddr->getType()), + NativePointeeAddrSpace)); Address NativeParamAddr = CGF.CreateMemTemp(NativeParamType); CGF.EmitStoreOfScalar(TargetAddr, NativeParamAddr, /*Volatile=*/false, NativeParamType); @@ -3424,8 +3433,8 @@ void CGOpenMPRuntimeGPU::emitOutlinedFunctionCall( continue; } llvm::Value *TargetArg = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - NativeArg, - NativeArg->getType()->getPointerElementType()->getPointerTo()); + NativeArg, llvm::PointerType::getWithSamePointeeType( + cast<llvm::PointerType>(NativeArg->getType()), /*AddrSpace*/ 0)); TargetArgs.emplace_back( CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(TargetArg, TargetType)); } diff --git a/clang/lib/CodeGen/CGRecordLayout.h b/clang/lib/CodeGen/CGRecordLayout.h index e6665b72bcba..5a3bcdf72f7b 100644 --- a/clang/lib/CodeGen/CGRecordLayout.h +++ b/clang/lib/CodeGen/CGRecordLayout.h @@ -93,8 +93,8 @@ struct CGBitFieldInfo { CharUnits VolatileStorageOffset; CGBitFieldInfo() - : Offset(), Size(), IsSigned(), StorageSize(), StorageOffset(), - VolatileOffset(), VolatileStorageSize(), VolatileStorageOffset() {} + : Offset(), Size(), IsSigned(), StorageSize(), VolatileOffset(), + VolatileStorageSize() {} CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned, unsigned StorageSize, CharUnits StorageOffset) diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index cf8313f92587..6f85bca8a201 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -411,7 +411,7 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, continue; } llvm::Type *Type = - Types.ConvertTypeForMem(Field->getType(), /*ForBitFields=*/true); + Types.ConvertTypeForMem(Field->getType(), /*ForBitField=*/true); // If we don't have a run yet, or don't live within the previous run's // allocated storage then we allocate some storage and start a new run. if (Run == FieldEnd || BitOffset >= Tail) { diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index ef0068cd3b0c..520483bc08b6 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2109,42 +2109,35 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr, return (EarlyClobber ? "&{" : "{") + Register.str() + "}"; } -llvm::Value* -CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info, - LValue InputValue, QualType InputType, - std::string &ConstraintStr, - SourceLocation Loc) { - llvm::Value *Arg; +std::pair<llvm::Value*, llvm::Type *> CodeGenFunction::EmitAsmInputLValue( + const TargetInfo::ConstraintInfo &Info, LValue InputValue, + QualType InputType, std::string &ConstraintStr, SourceLocation Loc) { if (Info.allowsRegister() || !Info.allowsMemory()) { - if (CodeGenFunction::hasScalarEvaluationKind(InputType)) { - Arg = EmitLoadOfLValue(InputValue, Loc).getScalarVal(); - } else { - llvm::Type *Ty = ConvertType(InputType); - uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty); - if ((Size <= 64 && llvm::isPowerOf2_64(Size)) || - getTargetHooks().isScalarizableAsmOperand(*this, Ty)) { - Ty = llvm::IntegerType::get(getLLVMContext(), Size); - Ty = llvm::PointerType::getUnqual(Ty); + if (CodeGenFunction::hasScalarEvaluationKind(InputType)) + return {EmitLoadOfLValue(InputValue, Loc).getScalarVal(), nullptr}; - Arg = Builder.CreateLoad( - Builder.CreateBitCast(InputValue.getAddress(*this), Ty)); - } else { - Arg = InputValue.getPointer(*this); - ConstraintStr += '*'; - } + llvm::Type *Ty = ConvertType(InputType); + uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty); + if ((Size <= 64 && llvm::isPowerOf2_64(Size)) || + getTargetHooks().isScalarizableAsmOperand(*this, Ty)) { + Ty = llvm::IntegerType::get(getLLVMContext(), Size); + Ty = llvm::PointerType::getUnqual(Ty); + + return {Builder.CreateLoad( + Builder.CreateBitCast(InputValue.getAddress(*this), Ty)), + nullptr}; } - } else { - Arg = InputValue.getPointer(*this); - ConstraintStr += '*'; } - return Arg; + Address Addr = InputValue.getAddress(*this); + ConstraintStr += '*'; + return {Addr.getPointer(), Addr.getElementType()}; } -llvm::Value* CodeGenFunction::EmitAsmInput( - const TargetInfo::ConstraintInfo &Info, - const Expr *InputExpr, - std::string &ConstraintStr) { +std::pair<llvm::Value *, llvm::Type *> +CodeGenFunction::EmitAsmInput(const TargetInfo::ConstraintInfo &Info, + const Expr *InputExpr, + std::string &ConstraintStr) { // If this can't be a register or memory, i.e., has to be a constant // (immediate or symbolic), try to emit it as such. if (!Info.allowsRegister() && !Info.allowsMemory()) { @@ -2155,19 +2148,20 @@ llvm::Value* CodeGenFunction::EmitAsmInput( llvm::APSInt IntResult; if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), getContext())) - return llvm::ConstantInt::get(getLLVMContext(), IntResult); + return {llvm::ConstantInt::get(getLLVMContext(), IntResult), nullptr}; } Expr::EvalResult Result; if (InputExpr->EvaluateAsInt(Result, getContext())) - return llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt()); + return {llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt()), + nullptr}; } if (Info.allowsRegister() || !Info.allowsMemory()) if (CodeGenFunction::hasScalarEvaluationKind(InputExpr->getType())) - return EmitScalarExpr(InputExpr); + return {EmitScalarExpr(InputExpr), nullptr}; if (InputExpr->getStmtClass() == Expr::CXXThisExprClass) - return EmitScalarExpr(InputExpr); + return {EmitScalarExpr(InputExpr), nullptr}; InputExpr = InputExpr->IgnoreParenNoopCasts(getContext()); LValue Dest = EmitLValue(InputExpr); return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr, @@ -2209,6 +2203,7 @@ static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect, bool HasUnwindClobber, bool ReadOnly, bool ReadNone, bool NoMerge, const AsmStmt &S, const std::vector<llvm::Type *> &ResultRegTypes, + const std::vector<llvm::Type *> &ArgElemTypes, CodeGenFunction &CGF, std::vector<llvm::Value *> &RegResults) { if (!HasUnwindClobber) @@ -2224,6 +2219,15 @@ static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect, Result.addFnAttr(llvm::Attribute::ReadOnly); } + // Add elementtype attribute for indirect constraints. + for (auto Pair : llvm::enumerate(ArgElemTypes)) { + if (Pair.value()) { + auto Attr = llvm::Attribute::get( + CGF.getLLVMContext(), llvm::Attribute::ElementType, Pair.value()); + Result.addParamAttr(Pair.index(), Attr); + } + } + // Slap the source location of the inline asm into a !srcloc metadata on the // call. if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) @@ -2291,6 +2295,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { std::vector<llvm::Type *> ResultRegTypes; std::vector<llvm::Type *> ResultTruncRegTypes; std::vector<llvm::Type *> ArgTypes; + std::vector<llvm::Type *> ArgElemTypes; std::vector<llvm::Value*> Args; llvm::BitVector ResultTypeRequiresCast; @@ -2298,6 +2303,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { std::string InOutConstraints; std::vector<llvm::Value*> InOutArgs; std::vector<llvm::Type*> InOutArgTypes; + std::vector<llvm::Type*> InOutArgElemTypes; // Keep track of out constraints for tied input operand. std::vector<std::string> OutputConstraints; @@ -2399,21 +2405,19 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { std::max((uint64_t)LargestVectorWidth, VT->getPrimitiveSizeInBits().getKnownMinSize()); } else { - llvm::Type *DestAddrTy = Dest.getAddress(*this).getType(); - llvm::Value *DestPtr = Dest.getPointer(*this); + Address DestAddr = Dest.getAddress(*this); // Matrix types in memory are represented by arrays, but accessed through // vector pointers, with the alignment specified on the access operation. // For inline assembly, update pointer arguments to use vector pointers. // Otherwise there will be a mis-match if the matrix is also an // input-argument which is represented as vector. - if (isa<MatrixType>(OutExpr->getType().getCanonicalType())) { - DestAddrTy = llvm::PointerType::get( - ConvertType(OutExpr->getType()), - cast<llvm::PointerType>(DestAddrTy)->getAddressSpace()); - DestPtr = Builder.CreateBitCast(DestPtr, DestAddrTy); - } - ArgTypes.push_back(DestAddrTy); - Args.push_back(DestPtr); + if (isa<MatrixType>(OutExpr->getType().getCanonicalType())) + DestAddr = Builder.CreateElementBitCast( + DestAddr, ConvertType(OutExpr->getType())); + + ArgTypes.push_back(DestAddr.getType()); + ArgElemTypes.push_back(DestAddr.getElementType()); + Args.push_back(DestAddr.getPointer()); Constraints += "=*"; Constraints += OutputConstraint; ReadOnly = ReadNone = false; @@ -2423,9 +2427,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { InOutConstraints += ','; const Expr *InputExpr = S.getOutputExpr(i); - llvm::Value *Arg = EmitAsmInputLValue(Info, Dest, InputExpr->getType(), - InOutConstraints, - InputExpr->getExprLoc()); + llvm::Value *Arg; + llvm::Type *ArgElemType; + std::tie(Arg, ArgElemType) = EmitAsmInputLValue( + Info, Dest, InputExpr->getType(), InOutConstraints, + InputExpr->getExprLoc()); if (llvm::Type* AdjTy = getTargetHooks().adjustInlineAsmType(*this, OutputConstraint, @@ -2444,6 +2450,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { InOutConstraints += OutputConstraint; InOutArgTypes.push_back(Arg->getType()); + InOutArgElemTypes.push_back(ArgElemType); InOutArgs.push_back(Arg); } } @@ -2483,7 +2490,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { getTarget(), CGM, S, false /* No EarlyClobber */); std::string ReplaceConstraint (InputConstraint); - llvm::Value *Arg = EmitAsmInput(Info, InputExpr, Constraints); + llvm::Value *Arg; + llvm::Type *ArgElemType; + std::tie(Arg, ArgElemType) = EmitAsmInput(Info, InputExpr, Constraints); // If this input argument is tied to a larger output result, extend the // input to be the same size as the output. The LLVM backend wants to see @@ -2528,10 +2537,19 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { VT->getPrimitiveSizeInBits().getKnownMinSize()); ArgTypes.push_back(Arg->getType()); + ArgElemTypes.push_back(ArgElemType); Args.push_back(Arg); Constraints += InputConstraint; } + // Append the "input" part of inout constraints. + for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) { + ArgTypes.push_back(InOutArgTypes[i]); + ArgElemTypes.push_back(InOutArgElemTypes[i]); + Args.push_back(InOutArgs[i]); + } + Constraints += InOutConstraints; + // Labels SmallVector<llvm::BasicBlock *, 16> Transfer; llvm::BasicBlock *Fallthrough = nullptr; @@ -2546,21 +2564,15 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::BlockAddress::get(CurFn, Dest.getBlock()); Args.push_back(BA); ArgTypes.push_back(BA->getType()); + ArgElemTypes.push_back(nullptr); if (!Constraints.empty()) Constraints += ','; - Constraints += 'X'; + Constraints += 'i'; } Fallthrough = createBasicBlock("asm.fallthrough"); } } - // Append the "input" part of inout constraints last. - for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) { - ArgTypes.push_back(InOutArgTypes[i]); - Args.push_back(InOutArgs[i]); - } - Constraints += InOutConstraints; - bool HasUnwindClobber = false; // Clobbers @@ -2647,18 +2659,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { EmitBlock(Fallthrough); UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false, ReadOnly, ReadNone, InNoMergeAttributedStmt, S, - ResultRegTypes, *this, RegResults); + ResultRegTypes, ArgElemTypes, *this, RegResults); } else if (HasUnwindClobber) { llvm::CallBase *Result = EmitCallOrInvoke(IA, Args, ""); UpdateAsmCallInst(*Result, HasSideEffect, true, ReadOnly, ReadNone, - InNoMergeAttributedStmt, S, ResultRegTypes, *this, - RegResults); + InNoMergeAttributedStmt, S, ResultRegTypes, ArgElemTypes, + *this, RegResults); } else { llvm::CallInst *Result = Builder.CreateCall(IA, Args, getBundlesForFunclet(IA)); UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false, ReadOnly, ReadNone, InNoMergeAttributedStmt, S, - ResultRegTypes, *this, RegResults); + ResultRegTypes, ArgElemTypes, *this, RegResults); } assert(RegResults.size() == ResultRegTypes.size()); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 4c11f7d67534..0db59dd2624c 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -2584,7 +2584,67 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S, } } +static bool isSupportedByOpenMPIRBuilder(const OMPExecutableDirective &S) { + // Check for unsupported clauses + if (!S.clauses().empty()) { + // Currently no clause is supported + return false; + } + + // Check if we have a statement with the ordered directive. + // Visit the statement hierarchy to find a compound statement + // with a ordered directive in it. + if (const auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(S.getRawStmt())) { + if (const Stmt *SyntacticalLoop = CanonLoop->getLoopStmt()) { + for (const Stmt *SubStmt : SyntacticalLoop->children()) { + if (!SubStmt) + continue; + if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(SubStmt)) { + for (const Stmt *CSSubStmt : CS->children()) { + if (!CSSubStmt) + continue; + if (isa<OMPOrderedDirective>(CSSubStmt)) { + return false; + } + } + } + } + } + } + return true; +} + void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { + bool UseOMPIRBuilder = + CGM.getLangOpts().OpenMPIRBuilder && isSupportedByOpenMPIRBuilder(S); + if (UseOMPIRBuilder) { + auto &&CodeGenIRBuilder = [this, &S, UseOMPIRBuilder](CodeGenFunction &CGF, + PrePostActionTy &) { + // Use the OpenMPIRBuilder if enabled. + if (UseOMPIRBuilder) { + // Emit the associated statement and get its loop representation. + llvm::DebugLoc DL = SourceLocToDebugLoc(S.getBeginLoc()); + const Stmt *Inner = S.getRawStmt(); + llvm::CanonicalLoopInfo *CLI = + EmitOMPCollapsedCanonicalLoopNest(Inner, 1); + + llvm::OpenMPIRBuilder &OMPBuilder = + CGM.getOpenMPRuntime().getOMPBuilder(); + // Add SIMD specific metadata + OMPBuilder.applySimd(DL, CLI); + return; + } + }; + { + auto LPCRegion = + CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S); + OMPLexicalScope Scope(*this, S, OMPD_unknown); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, + CodeGenIRBuilder); + } + return; + } + ParentLoopDirectiveForScanRegion ScanRegion(*this, S); OMPFirstScanLoop = true; auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { @@ -4460,8 +4520,9 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( CGF.getContext().getASTRecordLayout(CaptureRecord); unsigned Offset = Layout.getFieldOffset(It->second->getFieldIndex()) / CharWidth; - (void)DI->EmitDeclareOfAutoVariable(SharedVar, ContextValue, - CGF.Builder, false); + if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo()) + (void)DI->EmitDeclareOfAutoVariable(SharedVar, ContextValue, + CGF.Builder, false); llvm::Instruction &Last = CGF.Builder.GetInsertBlock()->back(); // Get the call dbg.declare instruction we just created and update // its DIExpression to add offset to base address. @@ -4560,8 +4621,10 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( CGF.getContext().getDeclAlign(Pair.first)); Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; }); if (auto *DI = CGF.getDebugInfo()) - DI->EmitDeclareOfAutoVariable(Pair.first, Pair.second.getPointer(), - CGF.Builder, /*UsePointerValue*/ true); + if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo()) + (void)DI->EmitDeclareOfAutoVariable( + Pair.first, Pair.second.getPointer(), CGF.Builder, + /*UsePointerValue*/ true); } // Adjust mapping for internal locals by mapping actual memory instead of // a pointer to this memory. @@ -6046,6 +6109,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_inbranch: case OMPC_notinbranch: case OMPC_link: + case OMPC_indirect: case OMPC_use: case OMPC_novariants: case OMPC_nocontext: @@ -6789,7 +6853,7 @@ void CodeGenFunction::EmitOMPTargetDataDirective( public: explicit DevicePointerPrivActionTy(bool &PrivatizeDevicePointers) - : PrePostActionTy(), PrivatizeDevicePointers(PrivatizeDevicePointers) {} + : PrivatizeDevicePointers(PrivatizeDevicePointers) {} void Enter(CodeGenFunction &CGF) override { PrivatizeDevicePointers = true; } diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 482499da1b0f..c839376880c4 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -1178,7 +1178,7 @@ bool CodeGenModule::HasLTOVisibilityPublicStd(const CXXRecordDecl *RD) { return false; const DeclContext *DC = RD; - while (1) { + while (true) { auto *D = cast<Decl>(DC); DC = DC->getParent(); if (isa<TranslationUnitDecl>(DC->getRedeclContext())) { diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index e6adec6948af..50e1638924d1 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -740,7 +740,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, #include "clang/Basic/Sanitizers.def" #undef SANITIZER - } while (0); + } while (false); if (D) { bool NoSanitizeCoverage = false; @@ -882,6 +882,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, if (Offset) Fn->addFnAttr("patchable-function-prefix", std::to_string(Offset)); } + // Instruct that functions for COFF/CodeView targets should start with a + // patchable instruction, but only on x86/x64. Don't forward this to ARM/ARM64 + // backends as they don't need it -- instructions on these architectures are + // always atomically patchable at runtime. + if (CGM.getCodeGenOpts().HotPatch && + getContext().getTargetInfo().getTriple().isX86()) + Fn->addFnAttr("patchable-function", "prologue-short-redirect"); // Add no-jump-tables value. if (CGM.getCodeGenOpts().NoUseJumpTables) @@ -1595,9 +1602,9 @@ void CodeGenFunction::EmitBranchToCounterBlock( if (!InstrumentRegions || !isInstrumentedCondition(Cond)) return EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount, LH); - llvm::BasicBlock *ThenBlock = NULL; - llvm::BasicBlock *ElseBlock = NULL; - llvm::BasicBlock *NextBlock = NULL; + llvm::BasicBlock *ThenBlock = nullptr; + llvm::BasicBlock *ElseBlock = nullptr; + llvm::BasicBlock *NextBlock = nullptr; // Create the block we'll use to increment the appropriate counter. llvm::BasicBlock *CounterIncrBlock = createBasicBlock("lop.rhscnt"); @@ -2109,6 +2116,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, // Create the actual GEP. addr = Address(Builder.CreateInBoundsGEP( addr.getElementType(), addr.getPointer(), gepIndices, "array.begin"), + ConvertTypeForMem(eltType), addr.getAlignment()); } @@ -2246,32 +2254,36 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { // Unknown size indication requires no size computation. // Otherwise, evaluate and record it. - if (const Expr *size = vat->getSizeExpr()) { + if (const Expr *sizeExpr = vat->getSizeExpr()) { // It's possible that we might have emitted this already, // e.g. with a typedef and a pointer to it. - llvm::Value *&entry = VLASizeMap[size]; + llvm::Value *&entry = VLASizeMap[sizeExpr]; if (!entry) { - llvm::Value *Size = EmitScalarExpr(size); + llvm::Value *size = EmitScalarExpr(sizeExpr); // C11 6.7.6.2p5: // If the size is an expression that is not an integer constant // expression [...] each time it is evaluated it shall have a value // greater than zero. - if (SanOpts.has(SanitizerKind::VLABound) && - size->getType()->isSignedIntegerType()) { + if (SanOpts.has(SanitizerKind::VLABound)) { SanitizerScope SanScope(this); - llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType()); + llvm::Value *Zero = llvm::Constant::getNullValue(size->getType()); + clang::QualType SEType = sizeExpr->getType(); + llvm::Value *CheckCondition = + SEType->isSignedIntegerType() + ? Builder.CreateICmpSGT(size, Zero) + : Builder.CreateICmpUGT(size, Zero); llvm::Constant *StaticArgs[] = { - EmitCheckSourceLocation(size->getBeginLoc()), - EmitCheckTypeDescriptor(size->getType())}; - EmitCheck(std::make_pair(Builder.CreateICmpSGT(Size, Zero), - SanitizerKind::VLABound), - SanitizerHandler::VLABoundNotPositive, StaticArgs, Size); + EmitCheckSourceLocation(sizeExpr->getBeginLoc()), + EmitCheckTypeDescriptor(SEType)}; + EmitCheck(std::make_pair(CheckCondition, SanitizerKind::VLABound), + SanitizerHandler::VLABoundNotPositive, StaticArgs, size); } // Always zexting here would be wrong if it weren't // undefined behavior to have a negative bound. - entry = Builder.CreateIntCast(Size, SizeTy, /*signed*/ false); + // FIXME: What about when size's type is larger than size_t? + entry = Builder.CreateIntCast(size, SizeTy, /*signed*/ false); } } type = vat->getElementType(); @@ -2694,7 +2706,7 @@ void CodeGenFunction::emitAlignmentAssumptionCheck( SanitizerScope SanScope(this); if (!OffsetValue) - OffsetValue = Builder.getInt1(0); // no offset. + OffsetValue = Builder.getInt1(false); // no offset. llvm::Constant *StaticData[] = {EmitCheckSourceLocation(Loc), EmitCheckSourceLocation(SecondaryLoc), diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index f76ce8a6400d..6db888dcec08 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -46,7 +46,6 @@ namespace llvm { class BasicBlock; class LLVMContext; class MDNode; -class Module; class SwitchInst; class Twine; class Value; @@ -55,13 +54,11 @@ class CanonicalLoopInfo; namespace clang { class ASTContext; -class BlockDecl; class CXXDestructorDecl; class CXXForRangeStmt; class CXXTryStmt; class Decl; class LabelDecl; -class EnumConstantDecl; class FunctionDecl; class FunctionProtoType; class LabelStmt; @@ -80,7 +77,6 @@ class ObjCAtSynchronizedStmt; class ObjCAutoreleasePoolStmt; class OMPUseDevicePtrClause; class OMPUseDeviceAddrClause; -class ReturnsNonNullAttr; class SVETypeFlags; class OMPExecutableDirective; @@ -92,12 +88,10 @@ namespace CodeGen { class CodeGenTypes; class CGCallee; class CGFunctionInfo; -class CGRecordLayout; class CGBlockInfo; class CGCXXABI; class BlockByrefHelpers; class BlockByrefInfo; -class BlockFlags; class BlockFieldFlags; class RegionCodeGenTy; class TargetCodeGenInfo; @@ -182,6 +176,7 @@ template <> struct DominatingValue<Address> { struct saved_type { DominatingLLVMValue::saved_type SavedValue; + llvm::Type *ElementType; CharUnits Alignment; }; @@ -190,11 +185,11 @@ template <> struct DominatingValue<Address> { } static saved_type save(CodeGenFunction &CGF, type value) { return { DominatingLLVMValue::save(CGF, value.getPointer()), - value.getAlignment() }; + value.getElementType(), value.getAlignment() }; } static type restore(CodeGenFunction &CGF, saved_type value) { return Address(DominatingLLVMValue::restore(CGF, value.SavedValue), - value.Alignment); + value.ElementType, value.Alignment); } }; @@ -241,11 +236,10 @@ public: /// A jump destination is an abstract label, branching to which may /// require a jump out through normal cleanups. struct JumpDest { - JumpDest() : Block(nullptr), ScopeDepth(), Index(0) {} - JumpDest(llvm::BasicBlock *Block, - EHScopeStack::stable_iterator Depth, + JumpDest() : Block(nullptr), Index(0) {} + JumpDest(llvm::BasicBlock *Block, EHScopeStack::stable_iterator Depth, unsigned Index) - : Block(Block), ScopeDepth(Depth), Index(Index) {} + : Block(Block), ScopeDepth(Depth), Index(Index) {} bool isValid() const { return Block != nullptr; } llvm::BasicBlock *getBlock() const { return Block; } @@ -4677,13 +4671,14 @@ private: SmallVectorImpl<llvm::Value *> &IRCallArgs, unsigned &IRCallArgPos); - llvm::Value* EmitAsmInput(const TargetInfo::ConstraintInfo &Info, - const Expr *InputExpr, std::string &ConstraintStr); + std::pair<llvm::Value *, llvm::Type *> + EmitAsmInput(const TargetInfo::ConstraintInfo &Info, const Expr *InputExpr, + std::string &ConstraintStr); - llvm::Value* EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info, - LValue InputValue, QualType InputType, - std::string &ConstraintStr, - SourceLocation Loc); + std::pair<llvm::Value *, llvm::Type *> + EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info, LValue InputValue, + QualType InputType, std::string &ConstraintStr, + SourceLocation Loc); /// Attempts to statically evaluate the object size of E. If that /// fails, emits code to figure the size of E out for us. This is diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 36b7ce87336c..d534cf182f5a 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -565,7 +565,9 @@ void CodeGenModule::Release() { "__amdgpu_device_library_preserve_asan_functions_ptr", nullptr, llvm::GlobalVariable::NotThreadLocal); addCompilerUsedGlobal(Var); - getModule().addModuleFlag(llvm::Module::Override, "amdgpu_hostcall", 1); + if (!getModule().getModuleFlag("amdgpu_hostcall")) { + getModule().addModuleFlag(llvm::Module::Override, "amdgpu_hostcall", 1); + } } emitLLVMUsed(); @@ -610,7 +612,7 @@ void CodeGenModule::Release() { if (Context.getLangOpts().SemanticInterposition) // Require various optimization to respect semantic interposition. - getModule().setSemanticInterposition(1); + getModule().setSemanticInterposition(true); if (CodeGenOpts.EmitCodeView) { // Indicate that we want CodeView in the metadata. @@ -710,6 +712,9 @@ void CodeGenModule::Release() { 1); } + if (CodeGenOpts.IBTSeal) + getModule().addModuleFlag(llvm::Module::Override, "ibt-seal", 1); + // Add module metadata for return address signing (ignoring // non-leaf/all) and stack tagging. These are actually turned on by function // attributes, but we use module metadata to emit build attributes. This is @@ -1368,7 +1373,8 @@ static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD, } void CodeGenModule::UpdateMultiVersionNames(GlobalDecl GD, - const FunctionDecl *FD) { + const FunctionDecl *FD, + StringRef &CurName) { if (!FD->isMultiVersion()) return; @@ -1400,7 +1406,11 @@ void CodeGenModule::UpdateMultiVersionNames(GlobalDecl GD, if (ExistingRecord != std::end(Manglings)) Manglings.remove(&(*ExistingRecord)); auto Result = Manglings.insert(std::make_pair(OtherName, OtherGD)); - MangledDeclNames[OtherGD.getCanonicalDecl()] = Result.first->first(); + StringRef OtherNameRef = MangledDeclNames[OtherGD.getCanonicalDecl()] = + Result.first->first(); + // If this is the current decl is being created, make sure we update the name. + if (GD.getCanonicalDecl() == OtherGD.getCanonicalDecl()) + CurName = OtherNameRef; if (llvm::GlobalValue *Entry = GetGlobalValue(NonTargetName)) Entry->setName(OtherName); } @@ -1819,7 +1829,7 @@ CodeGenModule::getMostBaseClasses(const CXXRecordDecl *RD) { void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F) { - llvm::AttrBuilder B; + llvm::AttrBuilder B(F->getContext()); if (CodeGenOpts.UnwindTables) B.addAttribute(llvm::Attribute::UWTable); @@ -1982,7 +1992,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D, llvm::Function *F) { if (D->hasAttr<StrictFPAttr>()) { - llvm::AttrBuilder FuncAttrs; + llvm::AttrBuilder FuncAttrs(F->getContext()); FuncAttrs.addAttribute("strictfp"); F->addFnAttrs(FuncAttrs); } @@ -2092,12 +2102,12 @@ void CodeGenModule::setNonAliasAttributes(GlobalDecl GD, if (!D->getAttr<SectionAttr>()) F->addFnAttr("implicit-section-name", SA->getName()); - llvm::AttrBuilder Attrs; + llvm::AttrBuilder Attrs(F->getContext()); if (GetCPUAndFeaturesAttributes(GD, Attrs)) { // We know that GetCPUAndFeaturesAttributes will always have the // newest set, since it has the newest possible FunctionDecl, so the // new ones should replace the old. - llvm::AttrBuilder RemoveAttrs; + llvm::AttributeMask RemoveAttrs; RemoveAttrs.addAttribute("target-cpu"); RemoveAttrs.addAttribute("target-features"); RemoveAttrs.addAttribute("tune-cpu"); @@ -3479,6 +3489,7 @@ void CodeGenModule::emitMultiVersionFunctions() { void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { const auto *FD = cast<FunctionDecl>(GD.getDecl()); assert(FD && "Not a FunctionDecl?"); + assert(FD->isCPUDispatchMultiVersion() && "Not a multiversion function?"); const auto *DD = FD->getAttr<CPUDispatchAttr>(); assert(DD && "Not a cpu_dispatch Function?"); llvm::Type *DeclTy = getTypes().ConvertType(FD->getType()); @@ -3489,14 +3500,16 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { } StringRef ResolverName = getMangledName(GD); + UpdateMultiVersionNames(GD, FD, ResolverName); llvm::Type *ResolverType; GlobalDecl ResolverGD; - if (getTarget().supportsIFunc()) + if (getTarget().supportsIFunc()) { ResolverType = llvm::FunctionType::get( llvm::PointerType::get(DeclTy, Context.getTargetAddressSpace(FD->getType())), false); + } else { ResolverType = DeclTy; ResolverGD = GD; @@ -3688,8 +3701,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( } if (FD->isMultiVersion()) { - if (FD->hasAttr<TargetAttr>()) - UpdateMultiVersionNames(GD, FD); + UpdateMultiVersionNames(GD, FD, MangledName); if (!IsForDefinition) return GetOrCreateMultiVersionResolver(GD, Ty, FD); } @@ -3785,7 +3797,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( if (D) SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk); if (ExtraAttrs.hasFnAttrs()) { - llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex); + llvm::AttrBuilder B(F->getContext(), ExtraAttrs.getFnAttrs()); F->addFnAttrs(B); } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index f1565511f98a..e803022508a4 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -46,7 +46,6 @@ class GlobalValue; class DataLayout; class FunctionType; class LLVMContext; -class OpenMPIRBuilder; class IndexedInstrProfReader; } @@ -55,17 +54,13 @@ class ASTContext; class AtomicType; class FunctionDecl; class IdentifierInfo; -class ObjCMethodDecl; class ObjCImplementationDecl; -class ObjCCategoryImplDecl; -class ObjCProtocolDecl; class ObjCEncodeExpr; class BlockExpr; class CharUnits; class Decl; class Expr; class Stmt; -class InitListExpr; class StringLiteral; class NamedDecl; class ValueDecl; @@ -78,13 +73,10 @@ class AnnotateAttr; class CXXDestructorDecl; class Module; class CoverageSourceInfo; -class TargetAttr; class InitSegAttr; -struct ParsedTargetAttr; namespace CodeGen { -class CallArgList; class CodeGenFunction; class CodeGenTBAA; class CGCXXABI; @@ -93,8 +85,6 @@ class CGObjCRuntime; class CGOpenCLRuntime; class CGOpenMPRuntime; class CGCUDARuntime; -class BlockFieldFlags; -class FunctionArgList; class CoverageMappingModuleGen; class TargetCodeGenInfo; @@ -311,7 +301,7 @@ private: const TargetInfo &Target; std::unique_ptr<CGCXXABI> ABI; llvm::LLVMContext &VMContext; - std::string ModuleNameHash = ""; + std::string ModuleNameHash; std::unique_ptr<CodeGenTBAA> TBAA; @@ -345,7 +335,7 @@ private: /// for emission and therefore should only be output if they are actually /// used. If a decl is in this, then it is known to have not been referenced /// yet. - std::map<StringRef, GlobalDecl> DeferredDecls; + llvm::DenseMap<StringRef, GlobalDecl> DeferredDecls; /// This is a list of deferred decls which we have seen that *are* actually /// referenced. These get code generated when the module is done. @@ -1478,7 +1468,8 @@ private: llvm::Constant *GetOrCreateMultiVersionResolver(GlobalDecl GD, llvm::Type *DeclTy, const FunctionDecl *FD); - void UpdateMultiVersionNames(GlobalDecl GD, const FunctionDecl *FD); + void UpdateMultiVersionNames(GlobalDecl GD, const FunctionDecl *FD, + StringRef &CurName); llvm::Constant * GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, LangAS AddrSpace, diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index ab953c2c7d52..6657f2a91e3d 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -131,7 +131,7 @@ public: static_assert(LastHashType <= TooBig, "Too many types in HashType"); PGOHash(PGOHashVersion HashVersion) - : Working(0), Count(0), HashVersion(HashVersion), MD5() {} + : Working(0), Count(0), HashVersion(HashVersion) {} void combine(HashType Type); uint64_t finalize(); PGOHashVersion getHashVersion() const { return HashVersion; } diff --git a/clang/lib/CodeGen/CodeGenTBAA.h b/clang/lib/CodeGen/CodeGenTBAA.h index e8e006f41616..a65963596fe9 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.h +++ b/clang/lib/CodeGen/CodeGenTBAA.h @@ -29,7 +29,6 @@ namespace clang { class Type; namespace CodeGen { -class CGRecordLayout; // TBAAAccessKind - A kind of TBAA memory access descriptor. enum class TBAAAccessKind : unsigned { diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 77721510dfd0..4839e22c4b14 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -643,11 +643,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { llvm::Type *PointeeType = ConvertTypeForMem(ETy); if (PointeeType->isVoidTy()) PointeeType = llvm::Type::getInt8Ty(getLLVMContext()); - - unsigned AS = PointeeType->isFunctionTy() - ? getDataLayout().getProgramAddressSpace() - : Context.getTargetAddressSpace(ETy); - + unsigned AS = Context.getTargetAddressSpace(ETy); ResultType = llvm::PointerType::get(PointeeType, AS); break; } @@ -748,7 +744,13 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { llvm::Type *PointeeType = CGM.getLangOpts().OpenCL ? CGM.getGenericBlockLiteralType() : ConvertTypeForMem(FTy); - unsigned AS = Context.getTargetAddressSpace(FTy); + // Block pointers lower to function type. For function type, + // getTargetAddressSpace() returns default address space for + // function pointer i.e. program address space. Therefore, for block + // pointers, it is important to pass qualifiers when calling + // getTargetAddressSpace(), to ensure that we get the address space + // for data pointers and not function pointers. + unsigned AS = Context.getTargetAddressSpace(FTy.getQualifiers()); ResultType = llvm::PointerType::get(PointeeType, AS); break; } diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h index f8f7542e4c83..28b831222943 100644 --- a/clang/lib/CodeGen/CodeGenTypes.h +++ b/clang/lib/CodeGen/CodeGenTypes.h @@ -31,14 +31,9 @@ namespace clang { class ASTContext; template <typename> class CanQual; class CXXConstructorDecl; -class CXXDestructorDecl; class CXXMethodDecl; class CodeGenOptions; -class FieldDecl; class FunctionProtoType; -class ObjCInterfaceDecl; -class ObjCIvarDecl; -class PointerType; class QualType; class RecordDecl; class TagDecl; diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 1a15b09c7b2b..2979d92c8417 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -334,59 +334,6 @@ public: ArrayRef<llvm::Function *> CXXThreadLocalInits, ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override; - bool mayNeedDestruction(const VarDecl *VD) const { - if (VD->needsDestruction(getContext())) - return true; - - // If the variable has an incomplete class type (or array thereof), it - // might need destruction. - const Type *T = VD->getType()->getBaseElementTypeUnsafe(); - if (T->getAs<RecordType>() && T->isIncompleteType()) - return true; - - return false; - } - - /// Determine whether we will definitely emit this variable with a constant - /// initializer, either because the language semantics demand it or because - /// we know that the initializer is a constant. - // For weak definitions, any initializer available in the current translation - // is not necessarily reflective of the initializer used; such initializers - // are ignored unless if InspectInitForWeakDef is true. - bool - isEmittedWithConstantInitializer(const VarDecl *VD, - bool InspectInitForWeakDef = false) const { - VD = VD->getMostRecentDecl(); - if (VD->hasAttr<ConstInitAttr>()) - return true; - - // All later checks examine the initializer specified on the variable. If - // the variable is weak, such examination would not be correct. - if (!InspectInitForWeakDef && - (VD->isWeak() || VD->hasAttr<SelectAnyAttr>())) - return false; - - const VarDecl *InitDecl = VD->getInitializingDeclaration(); - if (!InitDecl) - return false; - - // If there's no initializer to run, this is constant initialization. - if (!InitDecl->hasInit()) - return true; - - // If we have the only definition, we don't need a thread wrapper if we - // will emit the value as a constant. - if (isUniqueGVALinkage(getContext().GetGVALinkageForVariable(VD))) - return !mayNeedDestruction(VD) && InitDecl->evaluateValue(); - - // Otherwise, we need a thread wrapper unless we know that every - // translation unit will emit the value as a constant. We rely on the - // variable being constant-initialized in every translation unit if it's - // constant-initialized in any translation unit, which isn't actually - // guaranteed by the standard but is necessary for sanity. - return InitDecl->hasConstantInitialization(); - } - bool usesThreadWrapperFunction(const VarDecl *VD) const override { return !isEmittedWithConstantInitializer(VD) || mayNeedDestruction(VD); @@ -697,8 +644,8 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( CharUnits VTablePtrAlign = CGF.CGM.getDynamicOffsetAlignment(ThisAddr.getAlignment(), RD, CGF.getPointerAlign()); - llvm::Value *VTable = - CGF.GetVTablePtr(Address(This, VTablePtrAlign), VTableTy, RD); + llvm::Value *VTable = CGF.GetVTablePtr( + Address(This, ThisAddr.getElementType(), VTablePtrAlign), VTableTy, RD); // Apply the offset. // On ARM64, to reserve extra space in virtual member function pointers, @@ -4525,8 +4472,7 @@ static void InitCatchParam(CodeGenFunction &CGF, // pad. The best solution is to fix the personality function. } else { // Pull the pointer for the reference type off. - llvm::Type *PtrTy = - cast<llvm::PointerType>(LLVMCatchTy)->getElementType(); + llvm::Type *PtrTy = LLVMCatchTy->getPointerElementType(); // Create the temporary and write the adjusted pointer into it. Address ExnPtrTmp = diff --git a/clang/lib/CodeGen/MacroPPCallbacks.h b/clang/lib/CodeGen/MacroPPCallbacks.h index 32906a000269..d249b5b0eb88 100644 --- a/clang/lib/CodeGen/MacroPPCallbacks.h +++ b/clang/lib/CodeGen/MacroPPCallbacks.h @@ -17,7 +17,6 @@ namespace llvm { class DIMacroFile; -class DIMacroNode; } namespace clang { class Preprocessor; diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 5971a7709304..e00ff2b68719 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -401,7 +401,9 @@ public: ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override; bool usesThreadWrapperFunction(const VarDecl *VD) const override { - return false; + return getContext().getLangOpts().isCompatibleWithMSVC( + LangOptions::MSVC2019_5) && + (!isEmittedWithConstantInitializer(VD) || mayNeedDestruction(VD)); } LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, QualType LValType) override; @@ -2397,11 +2399,97 @@ void MicrosoftCXXABI::EmitThreadLocalInitFuncs( } } +static llvm::GlobalValue *getTlsGuardVar(CodeGenModule &CGM) { + // __tls_guard comes from the MSVC runtime and reflects + // whether TLS has been initialized for a particular thread. + // It is set from within __dyn_tls_init by the runtime. + // Every library and executable has its own variable. + llvm::Type *VTy = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + llvm::Constant *TlsGuardConstant = + CGM.CreateRuntimeVariable(VTy, "__tls_guard"); + llvm::GlobalValue *TlsGuard = cast<llvm::GlobalValue>(TlsGuardConstant); + + TlsGuard->setThreadLocal(true); + + return TlsGuard; +} + +static llvm::FunctionCallee getDynTlsOnDemandInitFn(CodeGenModule &CGM) { + // __dyn_tls_on_demand_init comes from the MSVC runtime and triggers + // dynamic TLS initialization by calling __dyn_tls_init internally. + llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), {}, + /*isVarArg=*/false); + return CGM.CreateRuntimeFunction( + FTy, "__dyn_tls_on_demand_init", + llvm::AttributeList::get(CGM.getLLVMContext(), + llvm::AttributeList::FunctionIndex, + llvm::Attribute::NoUnwind), + /*Local=*/true); +} + +static void emitTlsGuardCheck(CodeGenFunction &CGF, llvm::GlobalValue *TlsGuard, + llvm::BasicBlock *DynInitBB, + llvm::BasicBlock *ContinueBB) { + llvm::LoadInst *TlsGuardValue = + CGF.Builder.CreateLoad(Address(TlsGuard, CharUnits::One())); + llvm::Value *CmpResult = + CGF.Builder.CreateICmpEQ(TlsGuardValue, CGF.Builder.getInt8(0)); + CGF.Builder.CreateCondBr(CmpResult, DynInitBB, ContinueBB); +} + +static void emitDynamicTlsInitializationCall(CodeGenFunction &CGF, + llvm::GlobalValue *TlsGuard, + llvm::BasicBlock *ContinueBB) { + llvm::FunctionCallee Initializer = getDynTlsOnDemandInitFn(CGF.CGM); + llvm::Function *InitializerFunction = + cast<llvm::Function>(Initializer.getCallee()); + llvm::CallInst *CallVal = CGF.Builder.CreateCall(InitializerFunction); + CallVal->setCallingConv(InitializerFunction->getCallingConv()); + + CGF.Builder.CreateBr(ContinueBB); +} + +static void emitDynamicTlsInitialization(CodeGenFunction &CGF) { + llvm::BasicBlock *DynInitBB = + CGF.createBasicBlock("dyntls.dyn_init", CGF.CurFn); + llvm::BasicBlock *ContinueBB = + CGF.createBasicBlock("dyntls.continue", CGF.CurFn); + + llvm::GlobalValue *TlsGuard = getTlsGuardVar(CGF.CGM); + + emitTlsGuardCheck(CGF, TlsGuard, DynInitBB, ContinueBB); + CGF.Builder.SetInsertPoint(DynInitBB); + emitDynamicTlsInitializationCall(CGF, TlsGuard, ContinueBB); + CGF.Builder.SetInsertPoint(ContinueBB); +} + LValue MicrosoftCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, QualType LValType) { - CGF.CGM.ErrorUnsupported(VD, "thread wrappers"); - return LValue(); + // Dynamic TLS initialization works by checking the state of a + // guard variable (__tls_guard) to see whether TLS initialization + // for a thread has happend yet. + // If not, the initialization is triggered on-demand + // by calling __dyn_tls_on_demand_init. + emitDynamicTlsInitialization(CGF); + + // Emit the variable just like any regular global variable. + + llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD); + llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType()); + + unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace(); + V = CGF.Builder.CreateBitCast(V, RealVarTy->getPointerTo(AS)); + + CharUnits Alignment = CGF.getContext().getDeclAlign(VD); + Address Addr(V, Alignment); + + LValue LV = VD->getType()->isReferenceType() + ? CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(), + AlignmentSource::Decl) + : CGF.MakeAddrLValue(Addr, LValType, AlignmentSource::Decl); + return LV; } static ConstantAddress getInitThreadEpochPtr(CodeGenModule &CGM) { diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp index f7b83c45022d..9fe7e5d1f5c3 100644 --- a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp +++ b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp @@ -156,6 +156,7 @@ public: CodeGenOpts.setDebuggerTuning(CI.getCodeGenOpts().getDebuggerTuning()); CodeGenOpts.DebugPrefixMap = CI.getInvocation().getCodeGenOpts().DebugPrefixMap; + CodeGenOpts.DebugStrictDwarf = CI.getCodeGenOpts().DebugStrictDwarf; } ~PCHContainerGenerator() override = default; diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 85089cdb2200..fb81169003fc 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -855,19 +855,19 @@ public: if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) { if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) { llvm::Function *Fn = cast<llvm::Function>(GV); - llvm::AttrBuilder B; + llvm::AttrBuilder B(GV->getContext()); B.addAttribute("wasm-import-module", Attr->getImportModule()); Fn->addFnAttrs(B); } if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) { llvm::Function *Fn = cast<llvm::Function>(GV); - llvm::AttrBuilder B; + llvm::AttrBuilder B(GV->getContext()); B.addAttribute("wasm-import-name", Attr->getImportName()); Fn->addFnAttrs(B); } if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) { llvm::Function *Fn = cast<llvm::Function>(GV); - llvm::AttrBuilder B; + llvm::AttrBuilder B(GV->getContext()); B.addAttribute("wasm-export-name", Attr->getExportName()); Fn->addFnAttrs(B); } @@ -1606,7 +1606,7 @@ static bool isSIMDVectorType(ASTContext &Context, QualType Ty) { static bool isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) { const RecordType *RT = Ty->getAs<RecordType>(); if (!RT) - return 0; + return false; const RecordDecl *RD = RT->getDecl(); // If this is a C++ record, check the bases first. @@ -6414,7 +6414,7 @@ public: // AAPCS guarantees that sp will be 8-byte aligned on any public interface, // however this is not necessarily true on taking any interrupt. Instruct // the backend to perform a realignment as part of the function prologue. - llvm::AttrBuilder B; + llvm::AttrBuilder B(Fn->getContext()); B.addStackAlignmentAttr(8); Fn->addFnAttrs(B); } @@ -8282,14 +8282,15 @@ public: LangAS getGlobalVarAddressSpace(CodeGenModule &CGM, const VarDecl *D) const override { - // Check if a global/static variable is defined within address space 1 + // Check if global/static variable is defined in address space + // 1~6 (__flash, __flash1, __flash2, __flash3, __flash4, __flash5) // but not constant. LangAS AS = D->getType().getAddressSpace(); - if (isTargetAddressSpace(AS) && toTargetAddressSpace(AS) == 1 && - !D->getType().isConstQualified()) + if (isTargetAddressSpace(AS) && 1 <= toTargetAddressSpace(AS) && + toTargetAddressSpace(AS) <= 6 && !D->getType().isConstQualified()) CGM.getDiags().Report(D->getLocation(), diag::err_verify_nonconst_addrspace) - << "__flash"; + << "__flash*"; return TargetCodeGenInfo::getGlobalVarAddressSpace(CGM, D); } @@ -8693,7 +8694,7 @@ Address HexagonABIInfo::EmitVAArgForHexagonLinux(CodeGenFunction &CGF, llvm::ConstantInt::get(CGF.Int32Ty, ArgSize), "__new_saved_reg_area_pointer"); - llvm::Value *UsingStack = 0; + llvm::Value *UsingStack = nullptr; UsingStack = CGF.Builder.CreateICmpSGT(__new_saved_reg_area_pointer, __saved_reg_area_end_pointer); @@ -8935,9 +8936,9 @@ private: llvm::Type *coerceKernelArgumentType(llvm::Type *Ty, unsigned FromAS, unsigned ToAS) const { // Single value types. - if (Ty->isPointerTy() && Ty->getPointerAddressSpace() == FromAS) - return llvm::PointerType::get( - cast<llvm::PointerType>(Ty)->getElementType(), ToAS); + auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(Ty); + if (PtrTy && PtrTy->getAddressSpace() == FromAS) + return llvm::PointerType::getWithSamePointeeType(PtrTy, ToAS); return Ty; } @@ -9304,16 +9305,9 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( if (FD) setFunctionDeclAttributes(FD, F, M); - const bool IsOpenCLKernel = - M.getLangOpts().OpenCL && FD && FD->hasAttr<OpenCLKernelAttr>(); const bool IsHIPKernel = M.getLangOpts().HIP && FD && FD->hasAttr<CUDAGlobalAttr>(); - const bool IsOpenMP = M.getLangOpts().OpenMP && !FD; - if ((IsOpenCLKernel || IsHIPKernel || IsOpenMP) && - (M.getTriple().getOS() == llvm::Triple::AMDHSA)) - F->addFnAttr("amdgpu-implicitarg-num-bytes", "56"); - if (IsHIPKernel) F->addFnAttr("uniform-work-group-size", "true"); @@ -9340,8 +9334,8 @@ llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer( return llvm::ConstantPointerNull::get(PT); auto &Ctx = CGM.getContext(); - auto NPT = llvm::PointerType::get(PT->getElementType(), - Ctx.getTargetAddressSpace(LangAS::opencl_generic)); + auto NPT = llvm::PointerType::getWithSamePointeeType( + PT, Ctx.getTargetAddressSpace(LangAS::opencl_generic)); return llvm::ConstantExpr::getAddrSpaceCast( llvm::ConstantPointerNull::get(NPT), PT); } @@ -10276,9 +10270,9 @@ ABIArgInfo SPIRVABIInfo::classifyKernelArgumentType(QualType Ty) const { llvm::Type *LTy = CGT.ConvertType(Ty); auto DefaultAS = getContext().getTargetAddressSpace(LangAS::Default); auto GlobalAS = getContext().getTargetAddressSpace(LangAS::cuda_device); - if (LTy->isPointerTy() && LTy->getPointerAddressSpace() == DefaultAS) { - LTy = llvm::PointerType::get( - cast<llvm::PointerType>(LTy)->getElementType(), GlobalAS); + auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(LTy); + if (PtrTy && PtrTy->getAddressSpace() == DefaultAS) { + LTy = llvm::PointerType::getWithSamePointeeType(PtrTy, GlobalAS); return ABIArgInfo::getDirect(LTy, 0, nullptr, false); } } @@ -11417,7 +11411,7 @@ TargetCodeGenInfo::createEnqueuedBlockKernel(CodeGenFunction &CGF, auto &C = CGF.getLLVMContext(); std::string Name = Invoke->getName().str() + "_kernel"; auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false); - auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name, + auto *F = llvm::Function::Create(FT, llvm::GlobalValue::ExternalLinkage, Name, &CGF.CGM.getModule()); auto IP = CGF.Builder.saveIP(); auto *BB = llvm::BasicBlock::Create(C, "entry", F); diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index aa8bbb60a75f..dfdb2f5f55bb 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -38,7 +38,6 @@ class ABIInfo; class CallArgList; class CodeGenFunction; class CGBlockInfo; -class CGFunctionInfo; /// TargetCodeGenInfo - This class organizes various target-specific /// codegeneration issues, like target-specific attributes, builtins and so diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 3b551ea94cc2..2e4ebc10e9ba 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -62,6 +62,7 @@ #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "clang/Driver/Types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" @@ -170,13 +171,11 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, : Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), - DriverTitle(Title), CCPrintStatReportFilename(), CCPrintOptionsFilename(), - CCPrintHeadersFilename(), CCLogDiagnosticsFilename(), - CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false), - CCLogDiagnostics(false), CCGenDiagnostics(false), - CCPrintProcessStats(false), TargetTriple(TargetTriple), - CCCGenericGCCName(""), Saver(Alloc), CheckInputsExist(true), - GenReproducer(false), SuppressMissingInputWarning(false) { + DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false), + CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), + CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc), + CheckInputsExist(true), GenReproducer(false), + SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. if (!this->VFS) this->VFS = llvm::vfs::getRealFileSystem(); @@ -328,7 +327,8 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || (PhaseArg = DAL.getLastArg(options::OPT__analyze)) || - (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { + (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) || + (PhaseArg = DAL.getLastArg(options::OPT_extract_api))) { FinalPhase = phases::Compile; // -S only runs up to the backend. @@ -369,7 +369,20 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { bool HasNostdlib = Args.hasArg(options::OPT_nostdlib); bool HasNostdlibxx = Args.hasArg(options::OPT_nostdlibxx); bool HasNodefaultlib = Args.hasArg(options::OPT_nodefaultlibs); + bool IgnoreUnused = false; for (Arg *A : Args) { + if (IgnoreUnused) + A->claim(); + + if (A->getOption().matches(options::OPT_start_no_unused_arguments)) { + IgnoreUnused = true; + continue; + } + if (A->getOption().matches(options::OPT_end_no_unused_arguments)) { + IgnoreUnused = false; + continue; + } + // Unfortunately, we have to parse some forwarding options (-Xassembler, // -Xlinker, -Xpreprocessor) because we either integrate their functionality // (assembler and preprocessor), or bypass a previous driver ('collect2'). @@ -437,7 +450,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { // Enforce -static if -miamcu is present. if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) - DAL->AddFlagArg(0, Opts.getOption(options::OPT_static)); + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_static)); // Add a default value of -mlinker-version=, if one was given and the user // didn't specify one. @@ -763,6 +776,18 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, llvm::Triple TT(Val); std::string NormalizedName = TT.normalize(); + // We want to expand the shortened versions of the triples passed in to + // the values used for the bitcode libraries for convenience. + if (TT.getVendor() == llvm::Triple::UnknownVendor || + TT.getOS() == llvm::Triple::UnknownOS) { + if (TT.getArch() == llvm::Triple::nvptx) + TT = llvm::Triple("nvptx-nvidia-cuda"); + else if (TT.getArch() == llvm::Triple::nvptx64) + TT = llvm::Triple("nvptx64-nvidia-cuda"); + else if (TT.getArch() == llvm::Triple::amdgcn) + TT = llvm::Triple("amdgcn-amd-amdhsa"); + } + // Make sure we don't have a duplicate triple. auto Duplicate = FoundNormalizedTriples.find(NormalizedName); if (Duplicate != FoundNormalizedTriples.end()) { @@ -1871,9 +1896,16 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } if (C.getArgs().hasArg(options::OPT_print_runtime_dir)) { - std::string CandidateRuntimePath = TC.getRuntimePath(); - if (getVFS().exists(CandidateRuntimePath)) - llvm::outs() << CandidateRuntimePath << '\n'; + std::string RuntimePath; + // Get the first existing path, if any. + for (auto Path : TC.getRuntimePaths()) { + if (getVFS().exists(Path)) { + RuntimePath = Path; + break; + } + } + if (!RuntimePath.empty()) + llvm::outs() << RuntimePath << '\n'; else llvm::outs() << TC.getCompilerRTPath() << '\n'; return false; @@ -3105,7 +3137,7 @@ class OffloadingActionBuilder final { // We will pass the device action as a host dependence, so we don't // need to do anything else with them. CudaDeviceActions.clear(); - return ABRT_Success; + return CompileDeviceOnly ? ABRT_Ignore_Host : ABRT_Success; } // By default, we produce an action for each device arch. @@ -3138,6 +3170,7 @@ class OffloadingActionBuilder final { assert(DeviceLinkerInputs.size() == GpuArchList.size() && "Linker inputs and GPU arch list sizes do not match."); + ActionList Actions; // Append a new link action for each device. unsigned I = 0; for (auto &LI : DeviceLinkerInputs) { @@ -3149,22 +3182,29 @@ class OffloadingActionBuilder final { OffloadAction::DeviceDependences DeviceLinkDeps; DeviceLinkDeps.add(*DeviceLinkAction, *ToolChains[0], GpuArchList[I], AssociatedOffloadKind); - AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps, - DeviceLinkAction->getType())); + Actions.push_back(C.MakeAction<OffloadAction>( + DeviceLinkDeps, DeviceLinkAction->getType())); ++I; } DeviceLinkerInputs.clear(); // Create a host object from all the device images by embedding them - // in a fat binary. + // in a fat binary for mixed host-device compilation. For device-only + // compilation, creates a fat binary. OffloadAction::DeviceDependences DDeps; - auto *TopDeviceLinkAction = - C.MakeAction<LinkJobAction>(AL, types::TY_Object); - DDeps.add(*TopDeviceLinkAction, *ToolChains[0], - nullptr, AssociatedOffloadKind); - - // Offload the host object to the host linker. - AL.push_back(C.MakeAction<OffloadAction>(DDeps, TopDeviceLinkAction->getType())); + if (!CompileDeviceOnly || !BundleOutput.hasValue() || + BundleOutput.getValue()) { + auto *TopDeviceLinkAction = C.MakeAction<LinkJobAction>( + Actions, + CompileDeviceOnly ? types::TY_HIP_FATBIN : types::TY_Object); + DDeps.add(*TopDeviceLinkAction, *ToolChains[0], nullptr, + AssociatedOffloadKind); + // Offload the host object to the host linker. + AL.push_back( + C.MakeAction<OffloadAction>(DDeps, TopDeviceLinkAction->getType())); + } else { + AL.append(Actions); + } } Action* appendLinkHostActions(ActionList &AL) override { return AL.back(); } @@ -3551,15 +3591,18 @@ public: return false; } - Action* makeHostLinkAction() { - // Build a list of device linking actions. - ActionList DeviceAL; + void appendDeviceLinkActions(ActionList &AL) { for (DeviceActionBuilder *SB : SpecializedBuilders) { if (!SB->isValid()) continue; - SB->appendLinkDeviceActions(DeviceAL); + SB->appendLinkDeviceActions(AL); } + } + Action *makeHostLinkAction() { + // Build a list of device linking actions. + ActionList DeviceAL; + appendDeviceLinkActions(DeviceAL); if (DeviceAL.empty()) return nullptr; @@ -3775,14 +3818,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, } } - // FIXME: Linking separate translation units for SPIR-V is not supported yet. - // It can be done either by LLVM IR linking before conversion of the final - // linked module to SPIR-V or external SPIR-V linkers can be used e.g. - // spirv-link. - if (C.getDefaultToolChain().getTriple().isSPIRV() && Inputs.size() > 1) { - Diag(clang::diag::warn_drv_spirv_linking_multiple_inputs_unsupported); - } - handleArguments(C, Args, Inputs, Actions); // Builder to be used to build offloading actions. @@ -3822,15 +3857,8 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // Queue linker inputs. if (Phase == phases::Link) { assert(Phase == PL.back() && "linking must be final compilation step."); - // Compilation phases are setup per language, however for SPIR-V the - // final linking phase is meaningless since the compilation phase - // produces the final binary. - // FIXME: OpenCL - we could strip linking phase out from OpenCL - // compilation phases if we could verify it is not needed by any target. - if (!C.getDefaultToolChain().getTriple().isSPIRV()) { - LinkerInputs.push_back(Current); - Current = nullptr; - } + LinkerInputs.push_back(Current); + Current = nullptr; break; } @@ -3888,6 +3916,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, } // Add a link action if necessary. + + if (LinkerInputs.empty()) { + Arg *FinalPhaseArg; + if (getFinalPhase(Args, &FinalPhaseArg) == phases::Link) + OffloadBuilder.appendDeviceLinkActions(Actions); + } + if (!LinkerInputs.empty()) { if (Action *Wrapper = OffloadBuilder.makeHostLinkAction()) LinkerInputs.push_back(Wrapper); @@ -4036,7 +4071,8 @@ Action *Driver::ConstructPhaseAction( OutputTy = types::TY_ModuleFile; } - if (Args.hasArg(options::OPT_fsyntax_only)) { + if (Args.hasArg(options::OPT_fsyntax_only) || + Args.hasArg(options::OPT_extract_api)) { // Syntax checks should not emit a PCH file OutputTy = types::TY_Nothing; } @@ -4064,6 +4100,8 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile); if (Args.hasArg(options::OPT_verify_pch)) return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing); + if (Args.hasArg(options::OPT_extract_api)) + return C.MakeAction<CompileJobAction>(Input, types::TY_API_INFO); return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC); } case phases::Backend: { diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index d31529748b62..403fac76f060 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Path.h" #include "llvm/Support/SpecialCaseList.h" +#include "llvm/Support/AArch64TargetParser.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h" @@ -641,10 +642,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor, options::OPT_fno_sanitize_memory_use_after_dtor, MsanUseAfterDtor); + MsanParamRetval = Args.hasFlag( + options::OPT_fsanitize_memory_param_retval, + options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval); NeedPIE |= !(TC.getTriple().isOSLinux() && TC.getTriple().getArch() == llvm::Triple::x86_64); } else { MsanUseAfterDtor = false; + MsanParamRetval = false; } if (AllAddedKinds & SanitizerKind::Thread) { @@ -1096,6 +1101,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (MsanUseAfterDtor) CmdArgs.push_back("-fsanitize-memory-use-after-dtor"); + if (MsanParamRetval) + CmdArgs.push_back("-fsanitize-memory-param-retval"); + // FIXME: Pass these parameters as function attributes, not as -llvm flags. if (!TsanMemoryAccess) { CmdArgs.push_back("-mllvm"); diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 50c89aaadc18..5fef1fb2ee5a 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -75,17 +75,16 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, const ArgList &Args) : D(D), Triple(T), Args(Args), CachedRTTIArg(GetRTTIArgument(Args)), CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)) { - std::string RuntimePath = getRuntimePath(); - if (getVFS().exists(RuntimePath)) - getLibraryPaths().push_back(RuntimePath); - - std::string StdlibPath = getStdlibPath(); - if (getVFS().exists(StdlibPath)) - getFilePaths().push_back(StdlibPath); + auto addIfExists = [this](path_list &List, const std::string &Path) { + if (getVFS().exists(Path)) + List.push_back(Path); + }; - std::string CandidateLibPath = getArchSpecificLibPath(); - if (getVFS().exists(CandidateLibPath)) - getFilePaths().push_back(CandidateLibPath); + for (const auto &Path : getRuntimePaths()) + addIfExists(getLibraryPaths(), Path); + for (const auto &Path : getStdlibPaths()) + addIfExists(getFilePaths(), Path); + addIfExists(getFilePaths(), getArchSpecificLibPath()); } void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) { @@ -110,6 +109,10 @@ bool ToolChain::useRelaxRelocations() const { return ENABLE_X86_RELAX_RELOCATIONS; } +bool ToolChain::defaultToIEEELongDouble() const { + return PPC_LINUX_DEFAULT_IEEELONGDOUBLE && getTriple().isOSLinux(); +} + SanitizerArgs ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const { SanitizerArgs SanArgs(*this, JobArgs, !SanitizerArgsChecked); @@ -485,16 +488,35 @@ const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, return Args.MakeArgString(getCompilerRT(Args, Component, Type)); } -std::string ToolChain::getRuntimePath() const { - SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "lib", getTripleString()); - return std::string(P.str()); +ToolChain::path_list ToolChain::getRuntimePaths() const { + path_list Paths; + auto addPathForTriple = [this, &Paths](const llvm::Triple &Triple) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "lib", Triple.str()); + Paths.push_back(std::string(P.str())); + }; + + addPathForTriple(getTriple()); + + // Android targets may include an API level at the end. We still want to fall + // back on a path without the API level. + if (getTriple().isAndroid() && + getTriple().getEnvironmentName() != "android") { + llvm::Triple TripleWithoutLevel = getTriple(); + TripleWithoutLevel.setEnvironmentName("android"); + addPathForTriple(TripleWithoutLevel); + } + + return Paths; } -std::string ToolChain::getStdlibPath() const { +ToolChain::path_list ToolChain::getStdlibPaths() const { + path_list Paths; SmallString<128> P(D.Dir); llvm::sys::path::append(P, "..", "lib", getTripleString()); - return std::string(P.str()); + Paths.push_back(std::string(P.str())); + + return Paths; } std::string ToolChain::getArchSpecificLibPath() const { diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp index f282f04b7931..6899f9360da5 100644 --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp @@ -16,6 +16,7 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" +#include "clang/Driver/Tool.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatAdapters.h" @@ -95,9 +96,9 @@ const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( if (II.isFilename()) CmdArgs.push_back(II.getFilename()); + bool HasLibm = false; if (Args.hasArg(options::OPT_l)) { auto Lm = Args.getAllArgValues(options::OPT_l); - bool HasLibm = false; for (auto &Lib : Lm) { if (Lib == "m") { HasLibm = true; @@ -131,9 +132,8 @@ const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( } AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn", - SubArchName, - /* bitcode SDL?*/ true, - /* PostClang Link? */ false); + SubArchName, /*isBitCodeSDL=*/true, + /*postClangLink=*/false); // Add an intermediate output file. CmdArgs.push_back("-o"); const char *OutputFileName = @@ -144,6 +144,26 @@ const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, InputInfo(&JA, Args.MakeArgString(OutputFileName)))); + + // If we linked in libm definitions late we run another round of optimizations + // to inline the definitions and fold what is foldable. + if (HasLibm) { + ArgStringList OptCmdArgs; + const char *OptOutputFileName = + getOutputFileName(C, OutputFilePrefix, "-linked-opt", "bc"); + addLLCOptArg(Args, OptCmdArgs); + OptCmdArgs.push_back(OutputFileName); + OptCmdArgs.push_back("-o"); + OptCmdArgs.push_back(OptOutputFileName); + const char *OptExec = + Args.MakeArgString(getToolChain().GetProgramPath("opt")); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), OptExec, OptCmdArgs, + InputInfo(&JA, Args.MakeArgString(OutputFileName)), + InputInfo(&JA, Args.MakeArgString(OptOutputFileName)))); + OutputFileName = OptOutputFileName; + } + return OutputFileName; } @@ -286,10 +306,22 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( const OptTable &Opts = getDriver().getOpts(); - if (DeviceOffloadKind != Action::OFK_OpenMP) { - for (Arg *A : Args) { - DAL->append(A); + if (DeviceOffloadKind == Action::OFK_OpenMP) { + for (Arg *A : Args) + if (!llvm::is_contained(*DAL, A)) + DAL->append(A); + + std::string Arch = DAL->getLastArgValue(options::OPT_march_EQ).str(); + if (Arch.empty()) { + checkSystemForAMDGPU(Args, *this, Arch); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch); } + + return DAL; + } + + for (Arg *A : Args) { + DAL->append(A); } if (!BoundArch.empty()) { diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index be13d6d583ce..ca0ca4bf4eea 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -11,6 +11,7 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/AArch64TargetParser.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/Host.h" @@ -98,12 +99,14 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text, Features.push_back("-sve2-sm4"); } - // +sve implies +f32mm if the base architecture is v8.6A, v8.7A, v9.1A or - // v9.2A. It isn't the case in general that sve implies both f64mm and f32mm + // +sve implies +f32mm if the base architecture is >= v8.6A (except v9A) + // It isn't the case in general that sve implies both f64mm and f32mm if ((ArchKind == llvm::AArch64::ArchKind::ARMV8_6A || ArchKind == llvm::AArch64::ArchKind::ARMV8_7A || + ArchKind == llvm::AArch64::ArchKind::ARMV8_8A || ArchKind == llvm::AArch64::ArchKind::ARMV9_1A || - ArchKind == llvm::AArch64::ArchKind::ARMV9_2A) && + ArchKind == llvm::AArch64::ArchKind::ARMV9_2A || + ArchKind == llvm::AArch64::ArchKind::ARMV9_3A) && Feature == "sve") Features.push_back("+f32mm"); } @@ -219,6 +222,7 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, void aarch64::getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, std::vector<StringRef> &Features, bool ForAS) { Arg *A; @@ -390,9 +394,11 @@ fp16_fml_fallthrough: } if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd || + std::find(ItBegin, ItEnd, "+v8.8a") != ItEnd || std::find(ItBegin, ItEnd, "+v9a") != ItEnd || std::find(ItBegin, ItEnd, "+v9.1a") != ItEnd || - std::find(ItBegin, ItEnd, "+v9.2a") != ItEnd) { + std::find(ItBegin, ItEnd, "+v9.2a") != ItEnd || + std::find(ItBegin, ItEnd, "+v9.3a") != ItEnd) { if (HasCrypto && !NoCrypto) { // Check if we have NOT disabled an algorithm with something like: // +crypto, -algorithm @@ -451,7 +457,8 @@ fp16_fml_fallthrough: } } - const char *Archs[] = {"+v8.6a", "+v8.7a", "+v9.1a", "+v9.2a"}; + const char *Archs[] = {"+v8.6a", "+v8.7a", "+v8.8a", + "+v9.1a", "+v9.2a", "+v9.3a"}; auto Pos = std::find_first_of(Features.begin(), Features.end(), std::begin(Archs), std::end(Archs)); if (Pos != std::end(Features)) @@ -459,10 +466,16 @@ fp16_fml_fallthrough: if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { - if (A->getOption().matches(options::OPT_mno_unaligned_access)) + if (A->getOption().matches(options::OPT_mno_unaligned_access)) { Features.push_back("+strict-align"); - } else if (Triple.isOSOpenBSD()) + if (!ForAS) + CmdArgs.push_back("-Wunaligned-access"); + } + } else if (Triple.isOSOpenBSD()) { Features.push_back("+strict-align"); + if (!ForAS) + CmdArgs.push_back("-Wunaligned-access"); + } if (Args.hasArg(options::OPT_ffixed_x1)) Features.push_back("+reserve-x1"); diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.h b/clang/lib/Driver/ToolChains/Arch/AArch64.h index d47c402d4a42..0cdc2ec725e0 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.h +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.h @@ -22,6 +22,7 @@ namespace aarch64 { void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, std::vector<llvm::StringRef> &Features, bool ForAS); diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 4013cf230026..16af9f6d7129 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/ARMTargetParser.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/Host.h" @@ -769,10 +770,12 @@ fp16_fml_fallthrough: } // Kernel code has more strict alignment requirements. - if (KernelOrKext) + if (KernelOrKext) { Features.push_back("+strict-align"); - else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, - options::OPT_munaligned_access)) { + if (!ForAS) + CmdArgs.push_back("-Wunaligned-access"); + } else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, + options::OPT_munaligned_access)) { if (A->getOption().matches(options::OPT_munaligned_access)) { // No v6M core supports unaligned memory access (v6M ARM ARM A3.2). if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) @@ -781,8 +784,11 @@ fp16_fml_fallthrough: // access either. else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline) D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base"; - } else + } else { Features.push_back("+strict-align"); + if (!ForAS) + CmdArgs.push_back("-Wunaligned-access"); + } } else { // Assume pre-ARMv6 doesn't support unaligned accesses. // @@ -801,14 +807,23 @@ fp16_fml_fallthrough: int VersionNum = getARMSubArchVersionNumber(Triple); if (Triple.isOSDarwin() || Triple.isOSNetBSD()) { if (VersionNum < 6 || - Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) + Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) { Features.push_back("+strict-align"); + if (!ForAS) + CmdArgs.push_back("-Wunaligned-access"); + } } else if (Triple.isOSLinux() || Triple.isOSNaCl() || Triple.isOSWindows()) { - if (VersionNum < 7) + if (VersionNum < 7) { Features.push_back("+strict-align"); - } else + if (!ForAS) + CmdArgs.push_back("-Wunaligned-access"); + } + } else { Features.push_back("+strict-align"); + if (!ForAS) + CmdArgs.push_back("-Wunaligned-access"); + } } // llvm does not support reserving registers in general. There is support diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.h b/clang/lib/Driver/ToolChains/Arch/ARM.h index 881b63bd36b9..862a2f2796be 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -13,6 +13,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" +#include "llvm/Support/ARMTargetParser.h" #include "llvm/Support/TargetParser.h" #include <string> #include <vector> diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 65347a38490e..4386e395bc6c 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -33,6 +33,7 @@ #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/Types.h" #include "clang/Driver/XRayArgs.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/llvm-config.h" @@ -346,7 +347,8 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: - aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS); + aarch64::getAArch64TargetFeatures(D, Triple, Args, CmdArgs, Features, + ForAS); break; case llvm::Triple::x86: case llvm::Triple::x86_64: @@ -1115,7 +1117,7 @@ static void RenderDebugInfoCompressionArgs(const ArgList &Args, StringRef Value = A->getValue(); if (Value == "none") { CmdArgs.push_back("--compress-debug-sections=none"); - } else if (Value == "zlib" || Value == "zlib-gnu") { + } else if (Value == "zlib") { if (llvm::zlib::isAvailable()) { CmdArgs.push_back( Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); @@ -1929,6 +1931,11 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, } } + if (Args.getLastArg(options::OPT_mfix4300)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mfix4300"); + } + if (Arg *A = Args.getLastArg(options::OPT_G)) { StringRef v = A->getValue(); CmdArgs.push_back("-mllvm"); @@ -2055,7 +2062,7 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, } } - bool IEEELongDouble = false; + bool IEEELongDouble = getToolChain().defaultToIEEELongDouble(); for (const Arg *A : Args.filtered(options::OPT_mabi_EQ)) { StringRef V = A->getValue(); if (V == "ieeelongdouble") @@ -2897,6 +2904,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, AssociativeMath = true; ReciprocalMath = true; SignedZeros = false; + ApproxFunc = true; TrappingMath = false; FPExceptionBehavior = ""; break; @@ -2904,6 +2912,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; + ApproxFunc = false; TrappingMath = true; FPExceptionBehavior = "strict"; @@ -2923,6 +2932,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, MathErrno = false; AssociativeMath = true; ReciprocalMath = true; + ApproxFunc = true; SignedZeros = false; TrappingMath = false; RoundingFPMath = false; @@ -2938,6 +2948,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, MathErrno = TC.IsMathErrnoDefault(); AssociativeMath = false; ReciprocalMath = false; + ApproxFunc = false; SignedZeros = true; // -fno_fast_math restores default denormal and fpcontract handling DenormalFPMath = DefaultDenormalFPMath; @@ -2956,7 +2967,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // If -ffp-model=strict has been specified on command line but // subsequent options conflict then emit warning diagnostic. if (HonorINFs && HonorNaNs && !AssociativeMath && !ReciprocalMath && - SignedZeros && TrappingMath && RoundingFPMath && + SignedZeros && TrappingMath && RoundingFPMath && !ApproxFunc && DenormalFPMath == llvm::DenormalMode::getIEEE() && DenormalFP32Math == llvm::DenormalMode::getIEEE() && FPContract.equals("off")) @@ -2989,7 +3000,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-fmath-errno"); if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && - !TrappingMath) + ApproxFunc && !TrappingMath) CmdArgs.push_back("-menable-unsafe-fp-math"); if (!SignedZeros) @@ -3040,7 +3051,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the // individual features enabled by -ffast-math instead of the option itself as // that's consistent with gcc's behaviour. - if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && + if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && ApproxFunc && ReciprocalMath && !SignedZeros && !TrappingMath && !RoundingFPMath) { CmdArgs.push_back("-ffast-math"); if (FPModel.equals("fast")) { @@ -3217,9 +3228,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, return; } // Check whether the target subarch supports the hardware TLS register - if (arm::getARMSubArchVersionNumber(EffectiveTriple) < 7 && - llvm::ARM::parseArch(EffectiveTriple.getArchName()) != - llvm::ARM::ArchKind::ARMV6T2) { + if (!arm::isHardTPSupported(EffectiveTriple)) { D.Diag(diag::err_target_unsupported_tp_hard) << EffectiveTriple.getArchName(); return; @@ -4589,6 +4598,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (JA.getType() == types::TY_RewrittenLegacyObjC) { CmdArgs.push_back("-rewrite-objc"); rewriteKind = RK_Fragile; + } else if (JA.getType() == types::TY_API_INFO) { + CmdArgs.push_back("-extract-api"); } else { assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!"); } @@ -5310,7 +5321,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // as errors, but until then, we can live with a warning being emitted by the // compiler. This way, Clang can be used to compile code with scalable vectors // and identify possible issues. - if (isa<BackendJobAction>(JA)) { + if (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || + isa<BackendJobAction>(JA)) { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-treat-scalable-fixed-error-as-warning"); } @@ -5813,6 +5825,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-ftype-visibility"); CmdArgs.push_back("default"); } + } else if (IsOpenMPDevice) { + // When compiling for the OpenMP device we want protected visibility by + // default. This prevents the device from accidenally preempting code on the + // host, makes the system more robust, and improves performance. + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back("protected"); } if (!RawTriple.isPS4()) @@ -5992,6 +6010,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + Args.AddLastArg(CmdArgs, options::OPT_fms_hotpatch); + if (TC.SupportsProfiling()) { Args.AddLastArg(CmdArgs, options::OPT_pg); @@ -6149,6 +6169,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(Twine("-fcf-protection=") + A->getValue())); } + if (IsUsingLTO) + Args.AddLastArg(CmdArgs, options::OPT_mibt_seal); + // Forward -f options with positive and negative forms; we translate these by // hand. Do not propagate PGO options to the GPU-side compilations as the // profile info is for the host-side compilation only. @@ -6663,6 +6686,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_dM); Args.AddLastArg(CmdArgs, options::OPT_dD); + Args.AddLastArg(CmdArgs, options::OPT_dI); Args.AddLastArg(CmdArgs, options::OPT_fmax_tokens_EQ); diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index 00e0490e069b..013cd2341e17 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H #include "MSVC.h" #include "clang/Basic/DebugInfoOptions.h" diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 407f81a2ae09..1d30090ca21c 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -286,13 +286,13 @@ void tools::addLinkerCompressDebugSectionsOption( const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) { // GNU ld supports --compress-debug-sections=none|zlib|zlib-gnu|zlib-gabi - // whereas zlib is an alias to zlib-gabi. Therefore -gz=none|zlib|zlib-gnu - // are translated to --compress-debug-sections=none|zlib|zlib-gnu. - // -gz is not translated since ld --compress-debug-sections option requires an + // whereas zlib is an alias to zlib-gabi and zlib-gnu is obsoleted. Therefore + // -gz=none|zlib are translated to --compress-debug-sections=none|zlib. -gz + // is not translated since ld --compress-debug-sections option requires an // argument. if (const Arg *A = Args.getLastArg(options::OPT_gz_EQ)) { StringRef V = A->getValue(); - if (V == "none" || V == "zlib" || V == "zlib-gnu") + if (V == "none" || V == "zlib") CmdArgs.push_back(Args.MakeArgString("--compress-debug-sections=" + V)); else TC.getDriver().Diag(diag::err_drv_unsupported_option_argument) @@ -832,6 +832,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, return; } + // Always link the static runtime for executable. + if (SanArgs.needsAsanRt()) + HelperStaticRuntimes.push_back("asan_static"); + // Each static runtime that has a DSO counterpart above is excluded below, // but runtimes that exist only as static are not affected by needsSharedRt. @@ -1186,10 +1190,9 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, options::OPT_fpie, options::OPT_fno_pie); - if (Triple.isOSWindows() && LastPICArg && - LastPICArg == - Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, - options::OPT_fPIE, options::OPT_fpie)) { + if (Triple.isOSWindows() && !Triple.isOSCygMing() && LastPICArg && + LastPICArg == Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, + options::OPT_fPIE, options::OPT_fpie)) { ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << LastPICArg->getSpelling() << Triple.str(); if (Triple.getArch() == llvm::Triple::x86_64) @@ -1724,7 +1727,7 @@ bool tools::GetSDLFromOffloadArchive( std::string OutputLib = D.GetTemporaryPath( Twine(Prefix + Lib + "-" + Arch + "-" + Target).str(), "a"); - C.addTempFile(C.getArgs().MakeArgString(OutputLib.c_str())); + C.addTempFile(C.getArgs().MakeArgString(OutputLib)); ArgStringList CmdArgs; SmallString<128> DeviceTriple; @@ -1747,20 +1750,20 @@ bool tools::GetSDLFromOffloadArchive( T.getToolChain().GetProgramPath("clang-offload-bundler")); ArgStringList UBArgs; - UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg.c_str())); - UBArgs.push_back(C.getArgs().MakeArgString(TypeArg.c_str())); - UBArgs.push_back(C.getArgs().MakeArgString(InputArg.c_str())); - UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg.c_str())); - UBArgs.push_back(C.getArgs().MakeArgString(OutputArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg)); + UBArgs.push_back(C.getArgs().MakeArgString(TypeArg)); + UBArgs.push_back(C.getArgs().MakeArgString(InputArg)); + UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg)); + UBArgs.push_back(C.getArgs().MakeArgString(OutputArg)); // Add this flag to not exit from clang-offload-bundler if no compatible // code object is found in heterogenous archive library. std::string AdditionalArgs("-allow-missing-bundles"); - UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs)); C.addCommand(std::make_unique<Command>( JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs, - InputInfo(&JA, C.getArgs().MakeArgString(OutputLib.c_str())))); + InputInfo(&JA, C.getArgs().MakeArgString(OutputLib)))); if (postClangLink) CC1Args.push_back("-mlink-builtin-bitcode"); diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index ee573b89bed1..7324339efaa6 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -612,8 +612,9 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(CubinF); } - AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "nvptx", GPUArch, - false, false); + AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "nvptx", + GPUArch, /*isBitCodeSDL=*/false, + /*postClangLink=*/false); // Find nvlink and pass it as "--nvlink-path=" argument of // clang-nvlink-wrapper. @@ -752,8 +753,9 @@ void CudaToolChain::addClangTargetOptions( addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, getTriple()); - AddStaticDeviceLibsPostLinking(getDriver(), DriverArgs, CC1Args, "nvptx", GpuArch, - /* bitcode SDL?*/ true, /* PostClang Link? */ true); + AddStaticDeviceLibsPostLinking(getDriver(), DriverArgs, CC1Args, "nvptx", + GpuArch, /*isBitCodeSDL=*/true, + /*postClangLink=*/true); } } diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index de635f5816cf..05c58a8f43a8 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -247,7 +247,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) @@ -295,7 +296,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, unsigned Major = ToolChain.getTriple().getOSMajorVersion(); bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14; - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Args.hasArg(options::OPT_static); @@ -358,7 +360,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { if (Args.hasArg(options::OPT_shared) || IsPIE) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); else diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp index a7afec6963a1..bd1600d060c8 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -109,7 +109,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); } @@ -131,7 +132,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); ToolChain.addProfileRTLibs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-Bdynamic"); @@ -191,9 +193,11 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> { std::vector<std::string> FP; - SmallString<128> P(getStdlibPath()); - llvm::sys::path::append(P, M.gccSuffix()); - FP.push_back(std::string(P.str())); + for (const std::string &Path : getStdlibPaths()) { + SmallString<128> P(Path); + llvm::sys::path::append(P, M.gccSuffix()); + FP.push_back(std::string(P.str())); + } return FP; }; diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 7aeadd84dfee..7a9570a686f4 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -487,7 +487,8 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { if (!isAndroid && !IsIAMCU) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { @@ -563,7 +564,8 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().addProfileRTLibs(Args, CmdArgs); if (D.CCCIsCXX() && - !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); @@ -578,7 +580,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Silence warnings when linking C code with a C++ '-stdlib' argument. Args.ClaimAllArgs(options::OPT_stdlib_EQ); - if (!Args.hasArg(options::OPT_nostdlib)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { if (IsStatic || IsStaticPIE) CmdArgs.push_back("--start-group"); @@ -692,7 +694,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, CmdArgs.push_back("--compress-debug-sections"); } else { StringRef Value = A->getValue(); - if (Value == "none" || Value == "zlib" || Value == "zlib-gnu") { + if (Value == "none" || Value == "zlib") { CmdArgs.push_back( Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); } else { diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index e413640abad3..af74b108e04e 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -324,6 +324,12 @@ ToolChain::RuntimeLibType Linux::GetDefaultRuntimeLibType() const { return Generic_ELF::GetDefaultRuntimeLibType(); } +unsigned Linux::GetDefaultDwarfVersion() const { + if (getTriple().isAndroid()) + return 4; + return ToolChain::GetDefaultDwarfVersion(); +} + ToolChain::CXXStdlibType Linux::GetDefaultCXXStdlibType() const { if (getTriple().isAndroid()) return ToolChain::CST_Libcxx; diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index a5ec33bd44f1..a5648d79d655 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -40,6 +40,7 @@ public: void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; RuntimeLibType GetDefaultRuntimeLibType() const override; + unsigned GetDefaultDwarfVersion() const override; CXXStdlibType GetDefaultCXXStdlibType() const override; bool IsAArch64OutlineAtomicsDefault(const llvm::opt::ArgList &Args) const override; diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 66e9d8ab525a..18cef288f018 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -47,7 +47,14 @@ // Make sure this comes before MSVCSetupApi.h #include <comdef.h> +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif #include "MSVCSetupApi.h" +#ifdef __clang__ +#pragma clang diagnostic pop +#endif #include "llvm/Support/COM.h" _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); @@ -511,6 +518,11 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7)) CmdArgs.push_back("-debug"); + // If we specify /hotpatch, let the linker add padding in front of each + // function, like MSVC does. + if (Args.hasArg(options::OPT_fms_hotpatch, options::OPT__SLASH_hotpatch)) + CmdArgs.push_back("-functionpadmin"); + // Pass on /Brepro if it was passed to the compiler. // Note that /Brepro maps to -mno-incremental-linker-compatible. bool DefaultIncrementalLinkerCompatible = @@ -1333,6 +1345,15 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "Include", windowsSDKIncludeVersion, "winrt"); + if (major >= 10) { + llvm::VersionTuple Tuple; + if (!Tuple.tryParse(windowsSDKIncludeVersion) && + Tuple.getSubminor().getValueOr(0) >= 17134) { + AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, + "Include", windowsSDKIncludeVersion, + "cppwinrt"); + } + } } else { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "Include"); diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index 8f033de09bf6..c842773996ed 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -69,6 +69,10 @@ public: return llvm::DebuggerKind::Default; } + unsigned GetDefaultDwarfVersion() const override { + return 4; + } + enum class SubDirectoryType { Bin, Include, diff --git a/clang/lib/Driver/ToolChains/MSVCSetupApi.h b/clang/lib/Driver/ToolChains/MSVCSetupApi.h index a890b85fd5e9..28e6e3e08e37 100644 --- a/clang/lib/Driver/ToolChains/MSVCSetupApi.h +++ b/clang/lib/Driver/ToolChains/MSVCSetupApi.h @@ -28,6 +28,11 @@ #pragma once +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif + // Constants // #ifndef E_NOTFOUND @@ -512,3 +517,7 @@ STDMETHODIMP GetSetupConfiguration(_Out_ ISetupConfiguration **ppConfiguration, #ifdef __cplusplus } #endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index ecce2f062bd7..0501f9737404 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -164,6 +164,9 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--enable-auto-image-base"); } + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + CmdArgs.push_back("-o"); const char *OutputFile = Output.getFilename(); // GCC implicitly adds an .exe extension if it is given an output file name @@ -486,10 +489,7 @@ bool toolchains::MinGW::isPIEDefault(const llvm::opt::ArgList &Args) const { return false; } -bool toolchains::MinGW::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64 || - getArch() == llvm::Triple::aarch64; -} +bool toolchains::MinGW::isPICDefaultForced() const { return true; } llvm::ExceptionHandling toolchains::MinGW::GetExceptionModel(const ArgList &Args) const { diff --git a/clang/lib/Driver/ToolChains/PPCLinux.cpp b/clang/lib/Driver/ToolChains/PPCLinux.cpp index af2e3a21a0af..e480d8bd8703 100644 --- a/clang/lib/Driver/ToolChains/PPCLinux.cpp +++ b/clang/lib/Driver/ToolChains/PPCLinux.cpp @@ -8,11 +8,51 @@ #include "PPCLinux.h" #include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +using namespace clang::driver; using namespace clang::driver::toolchains; using namespace llvm::opt; +using namespace llvm::sys; + +// Glibc older than 2.32 doesn't fully support IEEE float128. Here we check +// glibc version by looking at dynamic linker name. +static bool GlibcSupportsFloat128(const std::string &Linker) { + llvm::SmallVector<char, 16> Path; + + // Resolve potential symlinks to linker. + if (fs::real_path(Linker, Path)) + return false; + llvm::StringRef LinkerName = + path::filename(llvm::StringRef(Path.data(), Path.size())); + + // Since glibc 2.34, the installed .so file is not symlink anymore. But we can + // still safely assume it's newer than 2.32. + if (LinkerName.startswith("ld64.so")) + return true; + + if (!LinkerName.startswith("ld-2.")) + return false; + unsigned Minor = (LinkerName[5] - '0') * 10 + (LinkerName[6] - '0'); + if (Minor < 32) + return false; + + return true; +} + +PPCLinuxToolChain::PPCLinuxToolChain(const Driver &D, + const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Linux(D, Triple, Args) { + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { + StringRef ABIName = A->getValue(); + if (ABIName == "ieeelongdouble" && !SupportIEEEFloat128(D, Triple, Args)) + D.Diag(diag::warn_drv_unsupported_float_abi_by_lib) << ABIName; + } +} void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { @@ -26,3 +66,20 @@ void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, Linux::AddClangSystemIncludeArgs(DriverArgs, CC1Args); } + +bool PPCLinuxToolChain::SupportIEEEFloat128( + const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) const { + if (!Triple.isLittleEndian() || !Triple.isPPC64()) + return false; + + if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx)) + return true; + + bool HasUnsupportedCXXLib = + ToolChain::GetCXXStdlibType(Args) == CST_Libcxx && + GCCInstallation.getVersion().isOlderThan(12, 1, 0); + + return GlibcSupportsFloat128(Linux::getDynamicLinker(Args)) && + !(D.CCCIsCXX() && HasUnsupportedCXXLib); +} diff --git a/clang/lib/Driver/ToolChains/PPCLinux.h b/clang/lib/Driver/ToolChains/PPCLinux.h index b3ef7b61dc3a..e0318ae8a3a2 100644 --- a/clang/lib/Driver/ToolChains/PPCLinux.h +++ b/clang/lib/Driver/ToolChains/PPCLinux.h @@ -18,12 +18,15 @@ namespace toolchains { class LLVM_LIBRARY_VISIBILITY PPCLinuxToolChain : public Linux { public: PPCLinuxToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args) - : Linux(D, Triple, Args) {} + const llvm::opt::ArgList &Args); void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + +private: + bool SupportIEEEFloat128(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) const; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index 5783a733983a..bcf9147833dd 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -23,8 +23,6 @@ using namespace clang::driver; using namespace clang; using namespace llvm::opt; -using clang::driver::tools::AddLinkerInputs; - void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, diff --git a/clang/lib/Driver/ToolChains/SPIRV.cpp b/clang/lib/Driver/ToolChains/SPIRV.cpp index 50d03e79bbb0..27de69550853 100644 --- a/clang/lib/Driver/ToolChains/SPIRV.cpp +++ b/clang/lib/Driver/ToolChains/SPIRV.cpp @@ -70,3 +70,24 @@ clang::driver::Tool *SPIRVToolChain::getTool(Action::ActionClass AC) const { } return ToolChain::getTool(AC); } +clang::driver::Tool *SPIRVToolChain::buildLinker() const { + return new tools::SPIRV::Linker(*this); +} + +void SPIRV::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const ToolChain &ToolChain = getToolChain(); + std::string Linker = ToolChain.GetProgramPath(getShortName()); + ArgStringList CmdArgs; + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Args.MakeArgString(Linker), CmdArgs, + Inputs, Output)); +} diff --git a/clang/lib/Driver/ToolChains/SPIRV.h b/clang/lib/Driver/ToolChains/SPIRV.h index 229f7018e3b5..a16ae3ca51fa 100644 --- a/clang/lib/Driver/ToolChains/SPIRV.h +++ b/clang/lib/Driver/ToolChains/SPIRV.h @@ -39,6 +39,17 @@ public: const char *LinkingOutput) const override; }; +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) : Tool("SPIRV::Linker", "spirv-link", TC) {} + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + } // namespace SPIRV } // namespace tools @@ -68,6 +79,7 @@ public: protected: clang::driver::Tool *getTool(Action::ActionClass AC) const override; + Tool *buildLinker() const override; private: clang::driver::Tool *getTranslator() const; diff --git a/clang/lib/Driver/ToolChains/VEToolchain.cpp b/clang/lib/Driver/ToolChains/VEToolchain.cpp index 4cdeec7f9d8a..1e43796be1ff 100644 --- a/clang/lib/Driver/ToolChains/VEToolchain.cpp +++ b/clang/lib/Driver/ToolChains/VEToolchain.cpp @@ -48,7 +48,8 @@ VEToolChain::VEToolChain(const Driver &D, const llvm::Triple &Triple, // ${BINPATH}/../lib/ve-unknown-linux-gnu, (== getStdlibPath) // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPath) // ${SYSROOT}/opt/nec/ve/lib, - getFilePaths().push_back(getStdlibPath()); + for (auto &Path : getStdlibPaths()) + getFilePaths().push_back(std::move(Path)); getFilePaths().push_back(getArchSpecificLibPath()); getFilePaths().push_back(computeSysRoot() + "/opt/nec/ve/lib"); } diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index a7298a9a71bf..3614272a5f74 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -76,7 +76,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.AddFilePathLibArgs(Args, CmdArgs); const char *Crt1 = "crt1.o"; - const char *Entry = NULL; + const char *Entry = nullptr; // If crt1-command.o exists, it supports new-style commands, so use it. // Otherwise, use the old crt1.o. This is a temporary transition measure. diff --git a/clang/lib/Driver/ToolChains/WebAssembly.h b/clang/lib/Driver/ToolChains/WebAssembly.h index c84e59675946..b4c3082a089a 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/clang/lib/Driver/ToolChains/WebAssembly.h @@ -51,6 +51,7 @@ private: bool hasBlocksRuntime() const override; bool SupportsProfiling() const override; bool HasNativeLLVMSupport() const override; + unsigned GetDefaultDwarfVersion() const override { return 4; } void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 1bd187ad2fc0..8f6adc6c2ad1 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -143,6 +143,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_CXXModule: case TY_PP_CXXModule: case TY_AST: case TY_ModuleFile: case TY_PCH: case TY_LLVM_IR: case TY_LLVM_BC: + case TY_API_INFO: return true; } } diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp index a3d388a5ae44..589bf8d216ed 100644 --- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -704,7 +704,7 @@ static bool getLiteralInfo(SourceRange literalRange, } }; - while (1) { + while (true) { if (Suff::has("u", text)) { UpperU = false; } else if (Suff::has("U", text)) { diff --git a/clang/lib/Format/AffectedRangeManager.cpp b/clang/lib/Format/AffectedRangeManager.cpp index 7ad1f7070d0a..f69f65c5ddf1 100644 --- a/clang/lib/Format/AffectedRangeManager.cpp +++ b/clang/lib/Format/AffectedRangeManager.cpp @@ -27,6 +27,7 @@ bool AffectedRangeManager::computeAffectedLines( const AnnotatedLine *PreviousLine = nullptr; while (I != E) { AnnotatedLine *Line = *I; + assert(Line->First); Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First); // If a line is part of a preprocessor directive, it needs to be formatted @@ -59,13 +60,10 @@ bool AffectedRangeManager::computeAffectedLines( bool AffectedRangeManager::affectsCharSourceRange( const CharSourceRange &Range) { - for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(), - E = Ranges.end(); - I != E; ++I) { - if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) && - !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin())) + for (const CharSourceRange &R : Ranges) + if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), R.getBegin()) && + !SourceMgr.isBeforeInTranslationUnit(R.getEnd(), Range.getBegin())) return true; - } return false; } @@ -116,6 +114,7 @@ bool AffectedRangeManager::nonPPLineAffected( // affected. bool SomeFirstChildAffected = false; + assert(Line->First); for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) { // Determine whether 'Tok' was affected. if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines)) diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 4225d6b67b0e..b66584652bc8 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -341,6 +341,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { if (State.Stack.back().BreakBeforeClosingBrace && Current.closesBlockOrBlockTypeList(Style)) return true; + if (State.Stack.back().BreakBeforeClosingParen && Current.is(tok::r_paren)) + return true; if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection) return true; if (Style.Language == FormatStyle::LK_ObjC && @@ -485,7 +487,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { // different LineFormatter would be used otherwise. if (Previous.ClosesTemplateDeclaration) return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No; - if (Previous.is(TT_FunctionAnnotationRParen)) + if (Previous.is(TT_FunctionAnnotationRParen) && + State.Line->Type != LT_PreprocessorDirective) return true; if (Previous.is(TT_LeadingJavaAnnotation) && Current.isNot(tok::l_paren) && Current.isNot(TT_LeadingJavaAnnotation)) @@ -540,13 +543,15 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline, bool DryRun, unsigned ExtraSpaces) { const FormatToken &Current = *State.NextToken; + assert(State.NextToken->Previous); + const FormatToken &Previous = *State.NextToken->Previous; assert(!State.Stack.empty()); State.NoContinuation = false; if ((Current.is(TT_ImplicitStringLiteral) && - (Current.Previous->Tok.getIdentifierInfo() == nullptr || - Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() == + (Previous.Tok.getIdentifierInfo() == nullptr || + Previous.Tok.getIdentifierInfo()->getPPKeywordID() == tok::pp_not_keyword))) { unsigned EndColumn = SourceMgr.getSpellingColumnNumber(Current.WhitespaceRange.getEnd()); @@ -576,7 +581,9 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline, void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, unsigned ExtraSpaces) { FormatToken &Current = *State.NextToken; + assert(State.NextToken->Previous); const FormatToken &Previous = *State.NextToken->Previous; + if (Current.is(tok::equal) && (State.Line->First->is(tok::kw_for) || Current.NestingLevel == 0) && State.Stack.back().VariablePos == 0) { @@ -638,10 +645,12 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, State.Stack.back().ColonPos = FirstColonPos; } - // In "AlwaysBreak" mode, enforce wrapping directly after the parenthesis by - // disallowing any further line breaks if there is no line break after the - // opening parenthesis. Don't break if it doesn't conserve columns. - if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak && + // In "AlwaysBreak" or "BlockIndent" mode, enforce wrapping directly after the + // parenthesis by disallowing any further line breaks if there is no line + // break after the opening parenthesis. Don't break if it doesn't conserve + // columns. + if ((Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak || + Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) && (Previous.isOneOf(tok::l_paren, TT_TemplateOpener, tok::l_square) || (Previous.is(tok::l_brace) && Previous.isNot(BK_Block) && Style.Cpp11BracedListStyle)) && @@ -770,6 +779,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, bool DryRun) { FormatToken &Current = *State.NextToken; + assert(State.NextToken->Previous); const FormatToken &Previous = *State.NextToken->Previous; // Extra penalty that needs to be added because of the way certain line @@ -942,6 +952,10 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, opensProtoMessageField(*PreviousNonComment, Style))) State.Stack.back().BreakBeforeClosingBrace = true; + if (PreviousNonComment && PreviousNonComment->is(tok::l_paren)) + State.Stack.back().BreakBeforeClosingParen = + Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent; + if (State.Stack.back().AvoidBinPacking) { // If we are breaking after '(', '{', '<', or this is the break after a ':' // to start a member initializater list in a constructor, this should not @@ -1036,6 +1050,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { (!Current.Next || Current.Next->isOneOf(tok::semi, tok::kw_const, tok::l_brace))) return State.Stack[State.Stack.size() - 2].LastSpace; + if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent && + Current.is(tok::r_paren) && State.Stack.size() > 1) + return State.Stack[State.Stack.size() - 2].LastSpace; if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope()) return State.Stack[State.Stack.size() - 2].LastSpace; if (Current.is(tok::identifier) && Current.Next && @@ -1288,10 +1305,9 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, State.Stack[i].NoLineBreak = true; State.Stack[State.Stack.size() - 2].NestedBlockInlined = false; } - if (Previous && - (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) || - Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) && - !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) { + if (Previous && (Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr) || + (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) && + !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)))) { State.Stack.back().NestedBlockInlined = !Newline && hasNestedBlockInlined(Previous, Current, Style); } diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h index b1b2611263a9..0eb53cbd0293 100644 --- a/clang/lib/Format/ContinuationIndenter.h +++ b/clang/lib/Format/ContinuationIndenter.h @@ -203,15 +203,15 @@ struct ParenState { bool AvoidBinPacking, bool NoLineBreak) : Tok(Tok), Indent(Indent), LastSpace(LastSpace), NestedBlockIndent(Indent), IsAligned(false), - BreakBeforeClosingBrace(false), AvoidBinPacking(AvoidBinPacking), - BreakBeforeParameter(false), NoLineBreak(NoLineBreak), - NoLineBreakInOperand(false), LastOperatorWrapped(true), - ContainsLineBreak(false), ContainsUnwrappedBuilder(false), - AlignColons(true), ObjCSelectorNameFound(false), - HasMultipleNestedBlocks(false), NestedBlockInlined(false), - IsInsideObjCArrayLiteral(false), IsCSharpGenericTypeConstraint(false), - IsChainedConditional(false), IsWrappedConditional(false), - UnindentOperator(false) {} + BreakBeforeClosingBrace(false), BreakBeforeClosingParen(false), + AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), + NoLineBreak(NoLineBreak), NoLineBreakInOperand(false), + LastOperatorWrapped(true), ContainsLineBreak(false), + ContainsUnwrappedBuilder(false), AlignColons(true), + ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false), + NestedBlockInlined(false), IsInsideObjCArrayLiteral(false), + IsCSharpGenericTypeConstraint(false), IsChainedConditional(false), + IsWrappedConditional(false), UnindentOperator(false) {} /// \brief The token opening this parenthesis level, or nullptr if this level /// is opened by fake parenthesis. @@ -277,6 +277,13 @@ struct ParenState { /// was a newline after the beginning left brace. bool BreakBeforeClosingBrace : 1; + /// Whether a newline needs to be inserted before the block's closing + /// paren. + /// + /// We only want to insert a newline before the closing paren if there also + /// was a newline after the beginning left paren. + bool BreakBeforeClosingParen : 1; + /// Avoid bin packing, i.e. multiple parameters/elements on multiple /// lines, in this context. bool AvoidBinPacking : 1; @@ -362,6 +369,8 @@ struct ParenState { return IsAligned; if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace) return BreakBeforeClosingBrace; + if (BreakBeforeClosingParen != Other.BreakBeforeClosingParen) + return BreakBeforeClosingParen; if (QuestionColumn != Other.QuestionColumn) return QuestionColumn < Other.QuestionColumn; if (AvoidBinPacking != Other.AvoidBinPacking) diff --git a/clang/lib/Format/DefinitionBlockSeparator.cpp b/clang/lib/Format/DefinitionBlockSeparator.cpp new file mode 100644 index 000000000000..827564357f78 --- /dev/null +++ b/clang/lib/Format/DefinitionBlockSeparator.cpp @@ -0,0 +1,236 @@ +//===--- DefinitionBlockSeparator.cpp ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements DefinitionBlockSeparator, a TokenAnalyzer that inserts +/// or removes empty lines separating definition blocks like classes, structs, +/// functions, enums, and namespaces in between. +/// +//===----------------------------------------------------------------------===// + +#include "DefinitionBlockSeparator.h" +#include "llvm/Support/Debug.h" +#define DEBUG_TYPE "definition-block-separator" + +namespace clang { +namespace format { +std::pair<tooling::Replacements, unsigned> DefinitionBlockSeparator::analyze( + TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, + FormatTokenLexer &Tokens) { + assert(Style.SeparateDefinitionBlocks != FormatStyle::SDS_Leave); + AffectedRangeMgr.computeAffectedLines(AnnotatedLines); + tooling::Replacements Result; + separateBlocks(AnnotatedLines, Result, Tokens); + return {Result, 0}; +} + +void DefinitionBlockSeparator::separateBlocks( + SmallVectorImpl<AnnotatedLine *> &Lines, tooling::Replacements &Result, + FormatTokenLexer &Tokens) { + const bool IsNeverStyle = + Style.SeparateDefinitionBlocks == FormatStyle::SDS_Never; + const AdditionalKeywords &ExtraKeywords = Tokens.getKeywords(); + auto LikelyDefinition = [this, ExtraKeywords](const AnnotatedLine *Line, + bool ExcludeEnum = false) { + if ((Line->MightBeFunctionDecl && Line->mightBeFunctionDefinition()) || + Line->startsWithNamespace()) + return true; + FormatToken *CurrentToken = Line->First; + while (CurrentToken) { + if (CurrentToken->isOneOf(tok::kw_class, tok::kw_struct) || + (Style.isJavaScript() && CurrentToken->is(ExtraKeywords.kw_function))) + return true; + if (!ExcludeEnum && CurrentToken->is(tok::kw_enum)) + return true; + CurrentToken = CurrentToken->Next; + } + return false; + }; + unsigned NewlineCount = + (Style.SeparateDefinitionBlocks == FormatStyle::SDS_Always ? 1 : 0) + 1; + WhitespaceManager Whitespaces( + Env.getSourceManager(), Style, + Style.DeriveLineEnding + ? WhitespaceManager::inputUsesCRLF( + Env.getSourceManager().getBufferData(Env.getFileID()), + Style.UseCRLF) + : Style.UseCRLF); + for (unsigned I = 0; I < Lines.size(); ++I) { + const auto &CurrentLine = Lines[I]; + if (CurrentLine->InPPDirective) + continue; + FormatToken *TargetToken = nullptr; + AnnotatedLine *TargetLine; + auto OpeningLineIndex = CurrentLine->MatchingOpeningBlockLineIndex; + AnnotatedLine *OpeningLine = nullptr; + const auto IsAccessSpecifierToken = [](const FormatToken *Token) { + return Token->isAccessSpecifier() || Token->isObjCAccessSpecifier(); + }; + const auto InsertReplacement = [&](const int NewlineToInsert) { + assert(TargetLine); + assert(TargetToken); + + // Do not handle EOF newlines. + if (TargetToken->is(tok::eof)) + return; + if (IsAccessSpecifierToken(TargetToken) || + (OpeningLineIndex > 0 && + IsAccessSpecifierToken(Lines[OpeningLineIndex - 1]->First))) + return; + if (!TargetLine->Affected) + return; + Whitespaces.replaceWhitespace(*TargetToken, NewlineToInsert, + TargetToken->OriginalColumn, + TargetToken->OriginalColumn); + }; + const auto IsPPConditional = [&](const size_t LineIndex) { + const auto &Line = Lines[LineIndex]; + return Line->First->is(tok::hash) && Line->First->Next && + Line->First->Next->isOneOf(tok::pp_if, tok::pp_ifdef, tok::pp_else, + tok::pp_ifndef, tok::pp_elifndef, + tok::pp_elifdef, tok::pp_elif, + tok::pp_endif); + }; + const auto FollowingOtherOpening = [&]() { + return OpeningLineIndex == 0 || + Lines[OpeningLineIndex - 1]->Last->opensScope() || + IsPPConditional(OpeningLineIndex - 1); + }; + const auto HasEnumOnLine = [&]() { + FormatToken *CurrentToken = CurrentLine->First; + bool FoundEnumKeyword = false; + while (CurrentToken) { + if (CurrentToken->is(tok::kw_enum)) + FoundEnumKeyword = true; + else if (FoundEnumKeyword && CurrentToken->is(tok::l_brace)) + return true; + CurrentToken = CurrentToken->Next; + } + return FoundEnumKeyword && I + 1 < Lines.size() && + Lines[I + 1]->First->is(tok::l_brace); + }; + + bool IsDefBlock = false; + const auto MayPrecedeDefinition = [&](const int Direction = -1) { + assert(Direction >= -1); + assert(Direction <= 1); + const size_t OperateIndex = OpeningLineIndex + Direction; + assert(OperateIndex < Lines.size()); + const auto &OperateLine = Lines[OperateIndex]; + if (LikelyDefinition(OperateLine)) + return false; + + if (OperateLine->First->is(tok::comment)) + return true; + + // A single line identifier that is not in the last line. + if (OperateLine->First->is(tok::identifier) && + OperateLine->First == OperateLine->Last && + OperateIndex + 1 < Lines.size()) { + // UnwrappedLineParser's recognition of free-standing macro like + // Q_OBJECT may also recognize some uppercased type names that may be + // used as return type as that kind of macros, which is a bit hard to + // distinguish one from another purely from token patterns. Here, we + // try not to add new lines below those identifiers. + AnnotatedLine *NextLine = Lines[OperateIndex + 1]; + if (NextLine->MightBeFunctionDecl && + NextLine->mightBeFunctionDefinition() && + NextLine->First->NewlinesBefore == 1 && + OperateLine->First->is(TT_FunctionLikeOrFreestandingMacro)) + return true; + } + + if ((Style.isCSharp() && OperateLine->First->is(TT_AttributeSquare))) + return true; + return false; + }; + + if (HasEnumOnLine() && + !LikelyDefinition(CurrentLine, /*ExcludeEnum=*/true)) { + // We have no scope opening/closing information for enum. + IsDefBlock = true; + OpeningLineIndex = I; + while (OpeningLineIndex > 0 && MayPrecedeDefinition()) + --OpeningLineIndex; + OpeningLine = Lines[OpeningLineIndex]; + TargetLine = OpeningLine; + TargetToken = TargetLine->First; + if (!FollowingOtherOpening()) + InsertReplacement(NewlineCount); + else if (IsNeverStyle) + InsertReplacement(OpeningLineIndex != 0); + TargetLine = CurrentLine; + TargetToken = TargetLine->First; + while (TargetToken && !TargetToken->is(tok::r_brace)) + TargetToken = TargetToken->Next; + if (!TargetToken) { + while (I < Lines.size() && !Lines[I]->First->is(tok::r_brace)) + ++I; + } + } else if (CurrentLine->First->closesScope()) { + if (OpeningLineIndex > Lines.size()) + continue; + // Handling the case that opening brace has its own line, with checking + // whether the last line already had an opening brace to guard against + // misrecognition. + if (OpeningLineIndex > 0 && + Lines[OpeningLineIndex]->First->is(tok::l_brace) && + Lines[OpeningLineIndex - 1]->Last->isNot(tok::l_brace)) + --OpeningLineIndex; + OpeningLine = Lines[OpeningLineIndex]; + // Closing a function definition. + if (LikelyDefinition(OpeningLine)) { + IsDefBlock = true; + while (OpeningLineIndex > 0 && MayPrecedeDefinition()) + --OpeningLineIndex; + OpeningLine = Lines[OpeningLineIndex]; + TargetLine = OpeningLine; + TargetToken = TargetLine->First; + if (!FollowingOtherOpening()) { + // Avoid duplicated replacement. + if (TargetToken->isNot(tok::l_brace)) + InsertReplacement(NewlineCount); + } else if (IsNeverStyle) + InsertReplacement(OpeningLineIndex != 0); + } + } + + // Not the last token. + if (IsDefBlock && I + 1 < Lines.size()) { + OpeningLineIndex = I + 1; + TargetLine = Lines[OpeningLineIndex]; + TargetToken = TargetLine->First; + + // No empty line for continuously closing scopes. The token will be + // handled in another case if the line following is opening a + // definition. + if (!TargetToken->closesScope() && !IsPPConditional(OpeningLineIndex)) { + // Check whether current line may precede a definition line. + while (OpeningLineIndex + 1 < Lines.size() && + MayPrecedeDefinition(/*Direction=*/0)) + ++OpeningLineIndex; + TargetLine = Lines[OpeningLineIndex]; + if (!LikelyDefinition(TargetLine)) { + OpeningLineIndex = I + 1; + TargetLine = Lines[I + 1]; + TargetToken = TargetLine->First; + InsertReplacement(NewlineCount); + } + } else if (IsNeverStyle) + InsertReplacement(/*NewlineToInsert=*/1); + } + } + for (const auto &R : Whitespaces.generateReplacements()) + // The add method returns an Error instance which simulates program exit + // code through overloading boolean operator, thus false here indicates + // success. + if (Result.add(R)) + return; +} +} // namespace format +} // namespace clang diff --git a/clang/lib/Format/DefinitionBlockSeparator.h b/clang/lib/Format/DefinitionBlockSeparator.h new file mode 100644 index 000000000000..31c0f34d6e19 --- /dev/null +++ b/clang/lib/Format/DefinitionBlockSeparator.h @@ -0,0 +1,41 @@ +//===--- DefinitionBlockSeparator.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares DefinitionBlockSeparator, a TokenAnalyzer that inserts or +/// removes empty lines separating definition blocks like classes, structs, +/// functions, enums, and namespaces in between. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_FORMAT_DEFINITIONBLOCKSEPARATOR_H +#define LLVM_CLANG_LIB_FORMAT_DEFINITIONBLOCKSEPARATOR_H + +#include "TokenAnalyzer.h" +#include "WhitespaceManager.h" + +namespace clang { +namespace format { +class DefinitionBlockSeparator : public TokenAnalyzer { +public: + DefinitionBlockSeparator(const Environment &Env, const FormatStyle &Style) + : TokenAnalyzer(Env, Style) {} + + std::pair<tooling::Replacements, unsigned> + analyze(TokenAnnotator &Annotator, + SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, + FormatTokenLexer &Tokens) override; + +private: + void separateBlocks(SmallVectorImpl<AnnotatedLine *> &Lines, + tooling::Replacements &Result, FormatTokenLexer &Tokens); +}; +} // namespace format +} // namespace clang + +#endif diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index be01daa38929..04e2915e3af6 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -16,6 +16,7 @@ #include "AffectedRangeManager.h" #include "BreakableToken.h" #include "ContinuationIndenter.h" +#include "DefinitionBlockSeparator.h" #include "FormatInternal.h" #include "FormatTokenLexer.h" #include "NamespaceEndCommentsFixer.h" @@ -383,6 +384,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> { IO.enumCase(Value, "Align", FormatStyle::BAS_Align); IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign); IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak); + IO.enumCase(Value, "BlockIndent", FormatStyle::BAS_BlockIndent); // For backward compatibility. IO.enumCase(Value, "true", FormatStyle::BAS_Align); @@ -430,6 +432,15 @@ template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> { }; template <> +struct ScalarEnumerationTraits<FormatStyle::SeparateDefinitionStyle> { + static void enumeration(IO &IO, FormatStyle::SeparateDefinitionStyle &Value) { + IO.enumCase(Value, "Leave", FormatStyle::SDS_Leave); + IO.enumCase(Value, "Always", FormatStyle::SDS_Always); + IO.enumCase(Value, "Never", FormatStyle::SDS_Never); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> { static void enumeration(IO &IO, FormatStyle::SpaceAroundPointerQualifiersStyle &Value) { @@ -756,6 +767,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment); IO.mapOptional("PenaltyBreakFirstLessLess", Style.PenaltyBreakFirstLessLess); + IO.mapOptional("PenaltyBreakOpenParenthesis", + Style.PenaltyBreakOpenParenthesis); IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString); IO.mapOptional("PenaltyBreakTemplateDeclaration", Style.PenaltyBreakTemplateDeclaration); @@ -769,6 +782,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("RawStringFormats", Style.RawStringFormats); IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment); IO.mapOptional("ReflowComments", Style.ReflowComments); + IO.mapOptional("RemoveBracesLLVM", Style.RemoveBracesLLVM); + IO.mapOptional("SeparateDefinitionBlocks", Style.SeparateDefinitionBlocks); IO.mapOptional("ShortNamespaceLines", Style.ShortNamespaceLines); IO.mapOptional("SortIncludes", Style.SortIncludes); IO.mapOptional("SortJavaStaticImport", Style.SortJavaStaticImport); @@ -855,6 +870,7 @@ template <> struct MappingTraits<FormatStyle::SpaceBeforeParensCustom> { IO.mapOptional("AfterFunctionDeclarationName", Spacing.AfterFunctionDeclarationName); IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros); + IO.mapOptional("AfterOverloadedOperator", Spacing.AfterOverloadedOperator); IO.mapOptional("BeforeNonEmptyParentheses", Spacing.BeforeNonEmptyParentheses); } @@ -1193,12 +1209,14 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PointerAlignment = FormatStyle::PAS_Right; LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; + LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.Standard = FormatStyle::LS_Latest; LLVMStyle.UseCRLF = false; LLVMStyle.UseTab = FormatStyle::UT_Never; LLVMStyle.ReflowComments = true; + LLVMStyle.RemoveBracesLLVM = false; LLVMStyle.SpacesInParentheses = false; LLVMStyle.SpacesInSquareBrackets = false; LLVMStyle.SpaceInEmptyBlock = false; @@ -1232,6 +1250,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.PenaltyExcessCharacter = 1000000; LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60; LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19; + LLVMStyle.PenaltyBreakOpenParenthesis = 0; LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational; LLVMStyle.PenaltyIndentedWhitespace = 0; @@ -1732,6 +1751,45 @@ FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const { namespace { +class BracesRemover : public TokenAnalyzer { +public: + BracesRemover(const Environment &Env, const FormatStyle &Style) + : TokenAnalyzer(Env, Style) {} + + std::pair<tooling::Replacements, unsigned> + analyze(TokenAnnotator &Annotator, + SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, + FormatTokenLexer &Tokens) override { + AffectedRangeMgr.computeAffectedLines(AnnotatedLines); + tooling::Replacements Result; + removeBraces(AnnotatedLines, Result); + return {Result, 0}; + } + +private: + // Remove optional braces. + void removeBraces(SmallVectorImpl<AnnotatedLine *> &Lines, + tooling::Replacements &Result) { + const auto &SourceMgr = Env.getSourceManager(); + for (AnnotatedLine *Line : Lines) { + removeBraces(Line->Children, Result); + if (!Line->Affected) + continue; + for (FormatToken *Token = Line->First; Token; Token = Token->Next) { + if (!Token->Optional) + continue; + assert(Token->isOneOf(tok::l_brace, tok::r_brace)); + const auto Start = Token == Line->Last + ? Token->WhitespaceRange.getBegin() + : Token->Tok.getLocation(); + const auto Range = + CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc()); + cantFail(Result.add(tooling::Replacement(SourceMgr, Range, ""))); + } + } + } +}; + class JavaScriptRequoter : public TokenAnalyzer { public: JavaScriptRequoter(const Environment &Env, const FormatStyle &Style) @@ -1840,7 +1898,7 @@ public: WhitespaceManager Whitespaces( Env.getSourceManager(), Style, Style.DeriveLineEnding - ? inputUsesCRLF( + ? WhitespaceManager::inputUsesCRLF( Env.getSourceManager().getBufferData(Env.getFileID()), Style.UseCRLF) : Style.UseCRLF); @@ -1864,19 +1922,13 @@ public: } private: - static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF) { - size_t LF = Text.count('\n'); - size_t CR = Text.count('\r') * 2; - return LF == CR ? DefaultToCRLF : CR > LF; - } - bool hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) { for (const AnnotatedLine *Line : Lines) { if (hasCpp03IncompatibleFormat(Line->Children)) return true; for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) { - if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) { + if (!Tok->hasWhitespaceBefore()) { if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener)) return true; if (Tok->is(TT_TemplateCloser) && @@ -1895,10 +1947,8 @@ private: for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) { if (!Tok->is(TT_PointerOrReference)) continue; - bool SpaceBefore = - Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd(); - bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() != - Tok->Next->WhitespaceRange.getEnd(); + bool SpaceBefore = Tok->hasWhitespaceBefore(); + bool SpaceAfter = Tok->Next->hasWhitespaceBefore(); if (SpaceBefore && !SpaceAfter) ++AlignmentDiff; if (!SpaceBefore && SpaceAfter) @@ -2204,7 +2254,7 @@ private: unsigned St = Idx, End = Idx; while ((End + 1) < Tokens.size() && Tokens[End]->Next == Tokens[End + 1]) { - End++; + ++End; } auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(), Tokens[End]->Tok.getEndLoc()); @@ -2440,7 +2490,7 @@ std::string replaceCRLF(const std::string &Code) { do { Pos = Code.find("\r\n", LastPos); if (Pos == LastPos) { - LastPos++; + ++LastPos; continue; } if (Pos == std::string::npos) { @@ -2586,8 +2636,9 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, bool MainIncludeFound = false; bool FormattingOff = false; + // '[' must be the first and '-' the last character inside [...]. llvm::Regex RawStringRegex( - "R\"(([\\[A-Za-z0-9_{}#<>%:;.?*+/^&\\$|~!=,'\\-]|])*)\\("); + "R\"([][A-Za-z0-9_{}#<>%:;.?*+/^&\\$|~!=,'-]*)\\("); SmallVector<StringRef, 2> RawStringMatches; std::string RawStringTermination = ")\""; @@ -3038,6 +3089,11 @@ reformat(const FormatStyle &Style, StringRef Code, }); } + if (Style.isCpp() && Style.RemoveBracesLLVM) + Passes.emplace_back([&](const Environment &Env) { + return BracesRemover(Env, Expanded).process(); + }); + if (Style.Language == FormatStyle::LK_Cpp) { if (Style.FixNamespaceComments) Passes.emplace_back([&](const Environment &Env) { @@ -3050,6 +3106,11 @@ reformat(const FormatStyle &Style, StringRef Code, }); } + if (Style.SeparateDefinitionBlocks != FormatStyle::SDS_Leave) + Passes.emplace_back([&](const Environment &Env) { + return DefinitionBlockSeparator(Env, Expanded).process(); + }); + if (Style.isJavaScript() && Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) Passes.emplace_back([&](const Environment &Env) { return JavaScriptRequoter(Env, Expanded).process(); @@ -3138,6 +3199,16 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style, return NamespaceEndCommentsFixer(*Env, Style).process().first; } +tooling::Replacements separateDefinitionBlocks(const FormatStyle &Style, + StringRef Code, + ArrayRef<tooling::Range> Ranges, + StringRef FileName) { + auto Env = Environment::make(Code, FileName, Ranges); + if (!Env) + return {}; + return DefinitionBlockSeparator(*Env, Style).process().first; +} + tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, StringRef Code, ArrayRef<tooling::Range> Ranges, @@ -3181,6 +3252,8 @@ const char *StyleOptionHelpDescription = ".clang-format file located in one of the parent\n" "directories of the source file (or current\n" "directory for stdin).\n" + "Use -style=file:<format_file_path> to explicitly specify" + "the configuration file.\n" "Use -style=\"{key: value, ...}\" to set specific\n" "parameters, e.g.:\n" " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\""; @@ -3233,6 +3306,18 @@ const char *DefaultFormatStyle = "file"; const char *DefaultFallbackStyle = "LLVM"; +llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> +loadAndParseConfigFile(StringRef ConfigFile, llvm::vfs::FileSystem *FS, + FormatStyle *Style, bool AllowUnknownOptions) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = + FS->getBufferForFile(ConfigFile.str()); + if (auto EC = Text.getError()) + return EC; + if (auto EC = parseConfiguration(*Text.get(), Style, AllowUnknownOptions)) + return EC; + return Text; +} + llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, StringRef FallbackStyleName, StringRef Code, llvm::vfs::FileSystem *FS, @@ -3263,6 +3348,28 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, return Style; } + // User provided clang-format file using -style=file:path/to/format/file. + if (!Style.InheritsParentConfig && + StyleName.startswith_insensitive("file:")) { + auto ConfigFile = StyleName.substr(5); + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = + loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions); + if (auto EC = Text.getError()) + return make_string_error("Error reading " + ConfigFile + ": " + + EC.message()); + + LLVM_DEBUG(llvm::dbgs() + << "Using configuration file " << ConfigFile << "\n"); + + if (!Style.InheritsParentConfig) + return Style; + + // Search for parent configs starting from the parent directory of + // ConfigFile. + FileName = ConfigFile; + ChildFormatTextToApply.emplace_back(std::move(*Text)); + } + // If the style inherits the parent configuration it is a command line // configuration, which wants to inherit, so we have to skip the check of the // StyleName. @@ -3288,6 +3395,16 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, auto dropDiagnosticHandler = [](const llvm::SMDiagnostic &, void *) {}; + auto applyChildFormatTexts = [&](FormatStyle *Style) { + for (const auto &MemBuf : llvm::reverse(ChildFormatTextToApply)) { + auto EC = parseConfiguration(*MemBuf, Style, AllowUnknownOptions, + dropDiagnosticHandler); + // It was already correctly parsed. + assert(!EC); + static_cast<void>(EC); + } + }; + for (StringRef Directory = Path; !Directory.empty(); Directory = llvm::sys::path::parent_path(Directory)) { @@ -3308,19 +3425,16 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, if (Status && (Status->getType() == llvm::sys::fs::file_type::regular_file)) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = - FS->getBufferForFile(ConfigFile.str()); - if (std::error_code EC = Text.getError()) - return make_string_error(EC.message()); - if (std::error_code ec = - parseConfiguration(*Text.get(), &Style, AllowUnknownOptions)) { - if (ec == ParseError::Unsuitable) { + loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions); + if (auto EC = Text.getError()) { + if (EC == ParseError::Unsuitable) { if (!UnsuitableConfigFiles.empty()) UnsuitableConfigFiles.append(", "); UnsuitableConfigFiles.append(ConfigFile); continue; } return make_string_error("Error reading " + ConfigFile + ": " + - ec.message()); + EC.message()); } LLVM_DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n"); @@ -3330,14 +3444,7 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, return Style; LLVM_DEBUG(llvm::dbgs() << "Applying child configurations\n"); - - for (const auto &MemBuf : llvm::reverse(ChildFormatTextToApply)) { - auto Ec = parseConfiguration(*MemBuf, &Style, AllowUnknownOptions, - dropDiagnosticHandler); - // It was already correctly parsed. - assert(!Ec); - static_cast<void>(Ec); - } + applyChildFormatTexts(&Style); return Style; } @@ -3363,17 +3470,9 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, UnsuitableConfigFiles); if (!ChildFormatTextToApply.empty()) { - assert(ChildFormatTextToApply.size() == 1); - LLVM_DEBUG(llvm::dbgs() - << "Applying child configuration on fallback style\n"); - - auto Ec = - parseConfiguration(*ChildFormatTextToApply.front(), &FallbackStyle, - AllowUnknownOptions, dropDiagnosticHandler); - // It was already correctly parsed. - assert(!Ec); - static_cast<void>(Ec); + << "Applying child configurations on fallback style\n"); + applyChildFormatTexts(&FallbackStyle); } return FallbackStyle; diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp index 57f8a5a45cbb..59d6f29bb54d 100644 --- a/clang/lib/Format/FormatToken.cpp +++ b/clang/lib/Format/FormatToken.cpp @@ -189,6 +189,7 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) { bool HasSeparatingComment = false; for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) { + assert(ItemBegin); // Skip comments on their own line. while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment()) { ItemBegin = ItemBegin->Next; @@ -296,14 +297,11 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) { const CommaSeparatedList::ColumnFormat * CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters) const { const ColumnFormat *BestFormat = nullptr; - for (SmallVector<ColumnFormat, 4>::const_reverse_iterator - I = Formats.rbegin(), - E = Formats.rend(); - I != E; ++I) { - if (I->TotalWidth <= RemainingCharacters || I->Columns == 1) { - if (BestFormat && I->LineCount > BestFormat->LineCount) + for (const ColumnFormat &Format : llvm::reverse(Formats)) { + if (Format.TotalWidth <= RemainingCharacters || Format.Columns == 1) { + if (BestFormat && Format.LineCount > BestFormat->LineCount) break; - BestFormat = &*I; + BestFormat = &Format; } } return BestFormat; diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index d410ede32240..a64329802ee3 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -51,6 +51,7 @@ namespace format { TYPE(FunctionAnnotationRParen) \ TYPE(FunctionDeclarationName) \ TYPE(FunctionLBrace) \ + TYPE(FunctionLikeOrFreestandingMacro) \ TYPE(FunctionTypeLParen) \ TYPE(IfMacro) \ TYPE(ImplicitStringLiteral) \ @@ -95,6 +96,7 @@ namespace format { TYPE(PointerOrReference) \ TYPE(PureVirtualSpecifier) \ TYPE(RangeBasedForLoopColon) \ + TYPE(RecordLBrace) \ TYPE(RegexLiteral) \ TYPE(SelectorName) \ TYPE(StartOfName) \ @@ -442,6 +444,9 @@ public: /// This starts an array initializer. bool IsArrayInitializer = false; + /// Is optional and can be removed. + bool Optional = false; + /// If this token starts a block, this contains all the unwrapped lines /// in it. SmallVector<AnnotatedLine *, 1> Children; @@ -634,6 +639,12 @@ public: return WhitespaceRange.getEnd(); } + /// Returns \c true if the range of whitespace immediately preceding the \c + /// Token is not empty. + bool hasWhitespaceBefore() const { + return WhitespaceRange.getBegin() != WhitespaceRange.getEnd(); + } + prec::Level getPrecedence() const { return getBinOpPrecedence(Tok.getKind(), /*GreaterThanIsOperator=*/true, /*CPlusPlus11=*/true); diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 7736a7042f86..c9166f4b17aa 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -429,18 +429,21 @@ bool FormatTokenLexer::tryMergeLessLess() { if (Tokens.size() < 3) return false; - bool FourthTokenIsLess = false; - if (Tokens.size() > 3) - FourthTokenIsLess = (Tokens.end() - 4)[0]->is(tok::less); - auto First = Tokens.end() - 3; - if (First[2]->is(tok::less) || First[1]->isNot(tok::less) || - First[0]->isNot(tok::less) || FourthTokenIsLess) + if (First[0]->isNot(tok::less) || First[1]->isNot(tok::less)) return false; // Only merge if there currently is no whitespace between the two "<". - if (First[1]->WhitespaceRange.getBegin() != - First[1]->WhitespaceRange.getEnd()) + if (First[1]->hasWhitespaceBefore()) + return false; + + auto X = Tokens.size() > 3 ? First[-1] : nullptr; + auto Y = First[2]; + if ((X && X->is(tok::less)) || Y->is(tok::less)) + return false; + + // Do not remove a whitespace between the two "<" e.g. "operator< <>". + if (X && X->is(tok::kw_operator) && Y->is(tok::greater)) return false; First[0]->Tok.setKind(tok::lessless); @@ -461,8 +464,7 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, return false; unsigned AddLength = 0; for (unsigned i = 1; i < Kinds.size(); ++i) { - if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() != - First[i]->WhitespaceRange.getEnd()) + if (!First[i]->is(Kinds[i]) || First[i]->hasWhitespaceBefore()) return false; AddLength += First[i]->TokenText.size(); } diff --git a/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/clang/lib/Format/NamespaceEndCommentsFixer.cpp index 38ab5b9df76d..0c34c6126c21 100644 --- a/clang/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/clang/lib/Format/NamespaceEndCommentsFixer.cpp @@ -28,7 +28,7 @@ std::string computeName(const FormatToken *NamespaceTok) { assert(NamespaceTok && NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) && "expecting a namespace token"); - std::string name = ""; + std::string name; const FormatToken *Tok = NamespaceTok->getNextNonComment(); if (NamespaceTok->is(TT_NamespaceMacro)) { // Collects all the non-comment tokens between opening parenthesis @@ -224,7 +224,7 @@ std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze( return {Fixes, 0}; } - std::string AllNamespaceNames = ""; + std::string AllNamespaceNames; size_t StartLineIndex = SIZE_MAX; StringRef NamespaceTokenText; unsigned int CompactedNamespacesCount = 0; @@ -260,8 +260,9 @@ std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze( // remove end comment, it will be merged in next one updateEndComment(EndCommentPrevTok, std::string(), SourceMgr, &Fixes); } - CompactedNamespacesCount++; - AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames; + ++CompactedNamespacesCount; + if (!NamespaceName.empty()) + AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames; continue; } NamespaceName += AllNamespaceNames; diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp index 5a89225c7fc8..b3a4684bead1 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.cpp +++ b/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -88,11 +88,11 @@ std::pair<tooling::Replacements, unsigned> QualifierAlignmentFixer::analyze( // Don't make replacements that replace nothing. tooling::Replacements NonNoOpFixes; - for (auto I = Fixes.begin(), E = Fixes.end(); I != E; ++I) { - StringRef OriginalCode = Code.substr(I->getOffset(), I->getLength()); + for (const tooling::Replacement &Fix : Fixes) { + StringRef OriginalCode = Code.substr(Fix.getOffset(), Fix.getLength()); - if (!OriginalCode.equals(I->getReplacementText())) { - auto Err = NonNoOpFixes.add(*I); + if (!OriginalCode.equals(Fix.getReplacementText())) { + auto Err = NonNoOpFixes.add(Fix); if (Err) llvm::errs() << "Error adding replacements : " << llvm::toString(std::move(Err)) << "\n"; @@ -204,9 +204,9 @@ static void rotateTokens(const SourceManager &SourceMgr, replaceToken(SourceMgr, Fixes, Range, NewText); } -FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( +const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, FormatToken *Tok, + tooling::Replacements &Fixes, const FormatToken *Tok, const std::string &Qualifier, tok::TokenKind QualifierType) { // We only need to think about streams that begin with a qualifier. if (!Tok->is(QualifierType)) @@ -261,10 +261,8 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( // Move to the end of any template class members e.g. // `Foo<int>::iterator`. if (Next && Next->startsSequence(TT_TemplateCloser, tok::coloncolon, - tok::identifier)) { - Next = Next->Next->Next; + tok::identifier)) return Tok; - } assert(Next && "Missing template opener"); Next = Next->Next; } @@ -281,16 +279,16 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( return Tok; } -FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( +const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, FormatToken *Tok, + tooling::Replacements &Fixes, const FormatToken *Tok, const std::string &Qualifier, tok::TokenKind QualifierType) { // if Tok is an identifier and possibly a macro then don't convert. if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok)) return Tok; - FormatToken *Qual = Tok; - FormatToken *LastQual = Qual; + const FormatToken *Qual = Tok; + const FormatToken *LastQual = Qual; while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { LastQual = Qual; Qual = Qual->Next; @@ -326,7 +324,7 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( Tok->Previous->isOneOf(tok::star, tok::ampamp, tok::amp)) { return Tok; } - FormatToken *Next = Tok->Next; + const FormatToken *Next = Tok->Next; // The case `std::Foo<T> const` -> `const std::Foo<T> &&` while (Next && Next->isOneOf(tok::identifier, tok::coloncolon)) Next = Next->Next; @@ -334,6 +332,8 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( Next->Previous->startsSequence(tok::identifier, TT_TemplateOpener)) { // Read from to the end of the TemplateOpener to // TemplateCloser const ArrayRef<int> a; const ArrayRef<int> &a; + if (Next->is(tok::comment) && Next->getNextNonComment()) + Next = Next->getNextNonComment(); assert(Next->MatchingParen && "Missing template closer"); Next = Next->MatchingParen->Next; @@ -394,11 +394,12 @@ LeftRightQualifierAlignmentFixer::analyze( tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier); assert(QualifierToken != tok::identifier && "Unrecognised Qualifier"); - for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { - FormatToken *First = AnnotatedLines[I]->First; - const auto *Last = AnnotatedLines[I]->Last; + for (AnnotatedLine *Line : AnnotatedLines) { + FormatToken *First = Line->First; + const auto *Last = Line->Last; - for (auto *Tok = First; Tok && Tok != Last && Tok->Next; Tok = Tok->Next) { + for (const auto *Tok = First; Tok && Tok != Last && Tok->Next; + Tok = Tok->Next) { if (Tok->is(tok::comment)) continue; if (RightAlign) diff --git a/clang/lib/Format/QualifierAlignmentFixer.h b/clang/lib/Format/QualifierAlignmentFixer.h index 7abd25687564..30ef96b8b0a7 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.h +++ b/clang/lib/Format/QualifierAlignmentFixer.h @@ -72,17 +72,19 @@ public: static tok::TokenKind getTokenFromQualifier(const std::string &Qualifier); - FormatToken *analyzeRight(const SourceManager &SourceMgr, - const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, FormatToken *Tok, - const std::string &Qualifier, - tok::TokenKind QualifierType); + const FormatToken *analyzeRight(const SourceManager &SourceMgr, + const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, + const FormatToken *Tok, + const std::string &Qualifier, + tok::TokenKind QualifierType); - FormatToken *analyzeLeft(const SourceManager &SourceMgr, - const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, FormatToken *Tok, - const std::string &Qualifier, - tok::TokenKind QualifierType); + const FormatToken *analyzeLeft(const SourceManager &SourceMgr, + const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, + const FormatToken *Tok, + const std::string &Qualifier, + tok::TokenKind QualifierType); // is the Token a simple or qualifier type static bool isQualifierOrType(const FormatToken *Tok, diff --git a/clang/lib/Format/SortJavaScriptImports.cpp b/clang/lib/Format/SortJavaScriptImports.cpp index 77dc0d683e5f..e4107525a7ff 100644 --- a/clang/lib/Format/SortJavaScriptImports.cpp +++ b/clang/lib/Format/SortJavaScriptImports.cpp @@ -78,6 +78,7 @@ struct JsModuleReference { ABSOLUTE, // from 'something' RELATIVE_PARENT, // from '../*' RELATIVE, // from './*' + ALIAS, // import X = A.B; }; ReferenceCategory Category = ReferenceCategory::SIDE_EFFECT; // The URL imported, e.g. `import .. from 'url';`. Empty for `export {a, b};`. @@ -105,10 +106,12 @@ bool operator<(const JsModuleReference &LHS, const JsModuleReference &RHS) { return LHS.IsExport < RHS.IsExport; if (LHS.Category != RHS.Category) return LHS.Category < RHS.Category; - if (LHS.Category == JsModuleReference::ReferenceCategory::SIDE_EFFECT) - // Side effect imports might be ordering sensitive. Consider them equal so - // that they maintain their relative order in the stable sort below. - // This retains transitivity because LHS.Category == RHS.Category here. + if (LHS.Category == JsModuleReference::ReferenceCategory::SIDE_EFFECT || + LHS.Category == JsModuleReference::ReferenceCategory::ALIAS) + // Side effect imports and aliases might be ordering sensitive. Consider + // them equal so that they maintain their relative order in the stable sort + // below. This retains transitivity because LHS.Category == RHS.Category + // here. return false; // Empty URLs sort *last* (for export {...};). if (LHS.URL.empty() != RHS.URL.empty()) @@ -260,13 +263,13 @@ private: while (Start != References.end() && Start->FormattingOff) { // Skip over all imports w/ disabled formatting. ReferencesSorted.push_back(*Start); - Start++; + ++Start; } SmallVector<JsModuleReference, 16> SortChunk; while (Start != References.end() && !Start->FormattingOff) { // Skip over all imports w/ disabled formatting. SortChunk.push_back(*Start); - Start++; + ++Start; } llvm::stable_sort(SortChunk); mergeModuleReferences(SortChunk); @@ -338,10 +341,12 @@ private: // Stitch together the module reference start... Buffer += getSourceText(Reference.Range.getBegin(), Reference.SymbolsStart); // ... then the references in order ... - for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) { - if (I != Symbols.begin()) + if (!Symbols.empty()) { + Buffer += getSourceText(Symbols.front().Range); + for (const JsImportedSymbol &Symbol : llvm::drop_begin(Symbols)) { Buffer += ","; - Buffer += getSourceText(I->Range); + Buffer += getSourceText(Symbol.Range); + } } // ... followed by the module reference end. Buffer += getSourceText(Reference.SymbolsEnd, Reference.Range.getEnd()); @@ -359,6 +364,7 @@ private: bool AnyImportAffected = false; bool FormattingOff = false; for (auto *Line : AnnotatedLines) { + assert(Line->First); Current = Line->First; LineEnd = Line->Last; // clang-format comments toggle formatting on/off. @@ -395,6 +401,8 @@ private: JsModuleReference Reference; Reference.FormattingOff = FormattingOff; Reference.Range.setBegin(Start); + // References w/o a URL, e.g. export {A}, groups with RELATIVE. + Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE; if (!parseModuleReference(Keywords, Reference)) { if (!FirstNonImportLine) FirstNonImportLine = Line; // if no comment before. @@ -410,9 +418,8 @@ private: << ", cat: " << Reference.Category << ", url: " << Reference.URL << ", prefix: " << Reference.Prefix; - for (size_t I = 0; I < Reference.Symbols.size(); ++I) - llvm::dbgs() << ", " << Reference.Symbols[I].Symbol << " as " - << Reference.Symbols[I].Alias; + for (const JsImportedSymbol &Symbol : Reference.Symbols) + llvm::dbgs() << ", " << Symbol.Symbol << " as " << Symbol.Alias; llvm::dbgs() << ", text: " << getSourceText(Reference.Range); llvm::dbgs() << "}\n"; }); @@ -461,9 +468,6 @@ private: Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE; else Reference.Category = JsModuleReference::ReferenceCategory::ABSOLUTE; - } else { - // w/o URL groups with "empty". - Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE; } return true; } @@ -499,6 +503,21 @@ private: nextToken(); if (Current->is(Keywords.kw_from)) return true; + // import X = A.B.C; + if (Current->is(tok::equal)) { + Reference.Category = JsModuleReference::ReferenceCategory::ALIAS; + nextToken(); + while (Current->is(tok::identifier)) { + nextToken(); + if (Current->is(tok::semi)) { + nextToken(); + return true; + } + if (!Current->is(tok::period)) + return false; + nextToken(); + } + } if (Current->isNot(tok::comma)) return false; nextToken(); // eat comma. diff --git a/clang/lib/Format/TokenAnalyzer.cpp b/clang/lib/Format/TokenAnalyzer.cpp index d83e837ca134..d0754e0c1112 100644 --- a/clang/lib/Format/TokenAnalyzer.cpp +++ b/clang/lib/Format/TokenAnalyzer.cpp @@ -127,11 +127,8 @@ std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process() { LLVM_DEBUG({ llvm::dbgs() << "Replacements for run " << Run << ":\n"; - for (tooling::Replacements::const_iterator I = RunResult.first.begin(), - E = RunResult.first.end(); - I != E; ++I) { - llvm::dbgs() << I->toString() << "\n"; - } + for (const tooling::Replacement &Fix : RunResult.first) + llvm::dbgs() << Fix.toString() << "\n"; }); for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { delete AnnotatedLines[i]; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 505a7250572b..9d130dbb02eb 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -75,7 +75,7 @@ public: : Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false), Keywords(Keywords) { Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false)); - resetTokenMetadata(CurrentToken); + resetTokenMetadata(); } private: @@ -780,6 +780,7 @@ private: unsigned CommaCount = 0; while (CurrentToken) { if (CurrentToken->is(tok::r_brace)) { + assert(Left->Optional == CurrentToken->Optional); Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; if (Style.AlignArrayOfStructures != FormatStyle::AIAS_None) { @@ -1409,8 +1410,8 @@ private: Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren); } - void resetTokenMetadata(FormatToken *Token) { - if (!Token) + void resetTokenMetadata() { + if (!CurrentToken) return; // Reset token type in case we have already looked at it and then @@ -1422,7 +1423,8 @@ private: TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator, TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral, TT_UntouchableMacroFunc, TT_ConstraintJunctions, - TT_StatementAttributeLikeMacro)) + TT_StatementAttributeLikeMacro, TT_FunctionLikeOrFreestandingMacro, + TT_RecordLBrace)) CurrentToken->setType(TT_Unknown); CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; @@ -1431,15 +1433,16 @@ private: } void next() { - if (CurrentToken) { - CurrentToken->NestingLevel = Contexts.size() - 1; - CurrentToken->BindingStrength = Contexts.back().BindingStrength; - modifyContext(*CurrentToken); - determineTokenType(*CurrentToken); - CurrentToken = CurrentToken->Next; - } + if (!CurrentToken) + return; + + CurrentToken->NestingLevel = Contexts.size() - 1; + CurrentToken->BindingStrength = Contexts.back().BindingStrength; + modifyContext(*CurrentToken); + determineTokenType(*CurrentToken); + CurrentToken = CurrentToken->Next; - resetTokenMetadata(CurrentToken); + resetTokenMetadata(); } /// A struct to hold information valid in a specific context, e.g. @@ -1563,9 +1566,9 @@ private: int ParenLevel = 0; while (Current) { if (Current->is(tok::l_paren)) - ParenLevel++; + ++ParenLevel; if (Current->is(tok::r_paren)) - ParenLevel--; + --ParenLevel; if (ParenLevel < 1) break; Current = Current->Next; @@ -1589,9 +1592,9 @@ private: break; } if (TemplateCloser->is(tok::less)) - NestingLevel++; + ++NestingLevel; if (TemplateCloser->is(tok::greater)) - NestingLevel--; + --NestingLevel; if (NestingLevel < 1) break; TemplateCloser = TemplateCloser->Next; @@ -1882,15 +1885,23 @@ private: FormatToken *LeftOfParens = Tok.MatchingParen->getPreviousNonComment(); if (LeftOfParens) { - // If there is a closing parenthesis left of the current parentheses, - // look past it as these might be chained casts. - if (LeftOfParens->is(tok::r_paren)) { + // If there is a closing parenthesis left of the current + // parentheses, look past it as these might be chained casts. + if (LeftOfParens->is(tok::r_paren) && + LeftOfParens->isNot(TT_CastRParen)) { if (!LeftOfParens->MatchingParen || !LeftOfParens->MatchingParen->Previous) return false; LeftOfParens = LeftOfParens->MatchingParen->Previous; } + // The Condition directly below this one will see the operator arguments + // as a (void *foo) cast. + // void operator delete(void *foo) ATTRIB; + if (LeftOfParens->Tok.getIdentifierInfo() && LeftOfParens->Previous && + LeftOfParens->Previous->is(tok::kw_operator)) + return false; + // If there is an identifier (or with a few exceptions a keyword) right // before the parentheses, this is unlikely to be a cast. if (LeftOfParens->Tok.getIdentifierInfo() && @@ -2343,9 +2354,10 @@ private: void TokenAnnotator::setCommentLineLevels( SmallVectorImpl<AnnotatedLine *> &Lines) { const AnnotatedLine *NextNonCommentLine = nullptr; - for (AnnotatedLine *AL : llvm::reverse(Lines)) { + for (AnnotatedLine *Line : llvm::reverse(Lines)) { + assert(Line->First); bool CommentLine = true; - for (const FormatToken *Tok = AL->First; Tok; Tok = Tok->Next) { + for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) { if (!Tok->is(tok::comment)) { CommentLine = false; break; @@ -2357,20 +2369,21 @@ void TokenAnnotator::setCommentLineLevels( if (NextNonCommentLine && CommentLine && NextNonCommentLine->First->NewlinesBefore <= 1 && NextNonCommentLine->First->OriginalColumn == - AL->First->OriginalColumn) { + Line->First->OriginalColumn) { // Align comments for preprocessor lines with the # in column 0 if // preprocessor lines are not indented. Otherwise, align with the next // line. - AL->Level = (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && - (NextNonCommentLine->Type == LT_PreprocessorDirective || - NextNonCommentLine->Type == LT_ImportStatement)) - ? 0 - : NextNonCommentLine->Level; + Line->Level = + (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && + (NextNonCommentLine->Type == LT_PreprocessorDirective || + NextNonCommentLine->Type == LT_ImportStatement)) + ? 0 + : NextNonCommentLine->Level; } else { - NextNonCommentLine = AL->First->isNot(tok::r_brace) ? AL : nullptr; + NextNonCommentLine = Line->First->isNot(tok::r_brace) ? Line : nullptr; } - setCommentLineLevels(AL->Children); + setCommentLineLevels(Line->Children); } } @@ -2549,11 +2562,8 @@ bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const { } void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { - for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(), - E = Line.Children.end(); - I != E; ++I) { - calculateFormattingInformation(**I); - } + for (AnnotatedLine *ChildLine : Line.Children) + calculateFormattingInformation(*ChildLine); Line.First->TotalLength = Line.First->IsMultiline ? Style.ColumnLimit @@ -2569,9 +2579,9 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { while (Current) { if (isFunctionDeclarationName(Style.isCpp(), *Current, Line)) Current->setType(TT_FunctionDeclarationName); + const FormatToken *Prev = Current->Previous; if (Current->is(TT_LineComment)) { - if (Current->Previous->is(BK_BracedInit) && - Current->Previous->opensScope()) + if (Prev->is(BK_BracedInit) && Prev->opensScope()) Current->SpacesRequiredBefore = (Style.Cpp11BracedListStyle && !Style.SpacesInParentheses) ? 0 : 1; else @@ -2612,12 +2622,11 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { Current->CanBreakBefore = Current->MustBreakBefore || canBreakBefore(Line, *Current); unsigned ChildSize = 0; - if (Current->Previous->Children.size() == 1) { - FormatToken &LastOfChild = *Current->Previous->Children[0]->Last; + if (Prev->Children.size() == 1) { + FormatToken &LastOfChild = *Prev->Children[0]->Last; ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit : LastOfChild.TotalLength + 1; } - const FormatToken *Prev = Current->Previous; if (Current->MustBreakBefore || Prev->Children.size() > 1 || (Prev->Children.size() == 1 && Prev->Children[0]->First->MustBreakBefore) || @@ -2857,6 +2866,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, Left.Previous->isOneOf(tok::identifier, tok::greater)) return 500; + if (Left.is(tok::l_paren) && Style.PenaltyBreakOpenParenthesis != 0) + return Style.PenaltyBreakOpenParenthesis; if (Left.is(tok::l_paren) && InFunctionDecl && Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign) return 100; @@ -2921,9 +2932,15 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, } bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const { - return Style.SpaceBeforeParens == FormatStyle::SBPO_Always || - (Style.SpaceBeforeParensOptions.BeforeNonEmptyParentheses && - Right.ParameterCount > 0); + if (Style.SpaceBeforeParens == FormatStyle::SBPO_Always) + return true; + if (Right.is(TT_OverloadedOperatorLParen) && + Style.SpaceBeforeParensOptions.AfterOverloadedOperator) + return true; + if (Style.SpaceBeforeParensOptions.BeforeNonEmptyParentheses && + Right.ParameterCount > 0) + return true; + return false; } bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, @@ -3290,9 +3307,11 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Right) { const FormatToken &Left = *Right.Previous; - auto HasExistingWhitespace = [&Right]() { - return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); - }; + + // If the token is finalized don't touch it (as it could be in a + // clang-format-off section). + if (Left.Finalized) + return Right.hasWhitespaceBefore(); if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo()) return true; // Never ever merge two identifiers. @@ -3307,7 +3326,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // or import .....; if (Left.is(Keywords.kw_import) && Right.isOneOf(tok::less, tok::ellipsis)) return true; - // No space between module :. + // Space between `module :` and `import :`. if (Left.isOneOf(Keywords.kw_module, Keywords.kw_import) && Right.is(TT_ModulePartitionColon)) return true; @@ -3321,12 +3340,18 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Left.is(tok::ellipsis) && Right.is(tok::identifier) && Line.First->is(Keywords.kw_import)) return false; + // Space in __attribute__((attr)) ::type. + if (Left.is(TT_AttributeParen) && Right.is(tok::coloncolon)) + return true; if (Left.is(tok::kw_operator)) return Right.is(tok::coloncolon); if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) && !Left.opensScope() && Style.SpaceBeforeCpp11BracedList) return true; + if (Left.is(tok::less) && Left.is(TT_OverloadedOperator) && + Right.is(TT_TemplateOpener)) + return true; } else if (Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) { if (Right.is(tok::period) && @@ -3351,7 +3376,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // Preserve the existence of a space before a percent for cases like 0x%04x // and "%d %d" if (Left.is(tok::numeric_constant) && Right.is(tok::percent)) - return HasExistingWhitespace(); + return Right.hasWhitespaceBefore(); } else if (Style.isJson()) { if (Right.is(tok::colon)) return false; @@ -3532,7 +3557,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; } if (Left.is(TT_ImplicitStringLiteral)) - return HasExistingWhitespace(); + return Right.hasWhitespaceBefore(); if (Line.Type == LT_ObjCMethodDecl) { if (Left.is(TT_ObjCMethodSpecifier)) return true; @@ -3617,11 +3642,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return Style.SpaceAfterCStyleCast || Right.isOneOf(TT_BinaryOperator, TT_SelectorName); - auto ShouldAddSpacesInAngles = [this, &HasExistingWhitespace]() { + auto ShouldAddSpacesInAngles = [this, &Right]() { if (this->Style.SpacesInAngles == FormatStyle::SIAS_Always) return true; if (this->Style.SpacesInAngles == FormatStyle::SIAS_Leave) - return HasExistingWhitespace(); + return Right.hasWhitespaceBefore(); return false; }; @@ -3647,7 +3672,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // Generally don't remove existing spaces between an identifier and "::". // The identifier might actually be a macro name such as ALWAYS_INLINE. If // this turns out to be too lenient, add analysis of the identifier itself. - return HasExistingWhitespace(); + return Right.hasWhitespaceBefore(); if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren)) // Put a space between < and :: in vector< ::std::string > @@ -3856,16 +3881,14 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, (Right.NewlinesBefore > 0 && Right.HasUnescapedNewline); if (Left.isTrailingComment()) return true; - if (Right.Previous->IsUnterminatedLiteral) + if (Left.IsUnterminatedLiteral) return true; - if (Right.is(tok::lessless) && Right.Next && - Right.Previous->is(tok::string_literal) && + if (Right.is(tok::lessless) && Right.Next && Left.is(tok::string_literal) && Right.Next->is(tok::string_literal)) return true; // Can break after template<> declaration - if (Right.Previous->ClosesTemplateDeclaration && - Right.Previous->MatchingParen && - Right.Previous->MatchingParen->NestingLevel == 0) { + if (Left.ClosesTemplateDeclaration && Left.MatchingParen && + Left.MatchingParen->NestingLevel == 0) { // Put concepts on the next line e.g. // template<typename T> // concept ... @@ -3898,9 +3921,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // has made a deliberate choice and might have aligned the contents of the // string literal accordingly. Thus, we try keep existing line breaks. return Right.IsMultiline && Right.NewlinesBefore > 0; - if ((Right.Previous->is(tok::l_brace) || - (Right.Previous->is(tok::less) && Right.Previous->Previous && - Right.Previous->Previous->is(tok::equal))) && + if ((Left.is(tok::l_brace) || (Left.is(tok::less) && Left.Previous && + Left.Previous->is(tok::equal))) && Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) { // Don't put enums or option definitions onto single lines in protocol // buffers. @@ -4004,7 +4026,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, Right.is(TT_SelectorName) && !Right.is(tok::r_square) && Right.Next) { // Keep `@submessage` together in: // @submessage { key: value } - if (Right.Previous && Right.Previous->is(tok::at)) + if (Left.is(tok::at)) return false; // Look for the scope opener after selector in cases like: // selector { ... @@ -4300,7 +4322,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Right.is(TT_ImplicitStringLiteral)) return false; - if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser)) + if (Right.is(TT_TemplateCloser)) return false; if (Right.is(tok::r_square) && Right.MatchingParen && Right.MatchingParen->is(TT_LambdaLSquare)) @@ -4311,6 +4333,18 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Right.is(tok::r_brace)) return Right.MatchingParen && Right.MatchingParen->is(BK_Block); + // We only break before r_paren if we're in a block indented context. + if (Right.is(tok::r_paren)) { + if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) { + return Right.MatchingParen && + !(Right.MatchingParen->Previous && + (Right.MatchingParen->Previous->is(tok::kw_for) || + Right.MatchingParen->Previous->isIf())); + } + + return false; + } + // Allow breaking after a trailing annotation, e.g. after a method // declaration. if (Left.is(TT_TrailingAnnotation)) diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h index 6e5e62cd4d82..ecd9dbb0f864 100644 --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -19,8 +19,6 @@ #include "clang/Format/Format.h" namespace clang { -class SourceManager; - namespace format { enum LineType { @@ -53,10 +51,9 @@ public: // left them in a different state. First->Previous = nullptr; FormatToken *Current = First; - for (auto I = ++Line.Tokens.begin(), E = Line.Tokens.end(); I != E; ++I) { - const UnwrappedLineNode &Node = *I; - Current->Next = I->Tok; - I->Tok->Previous = Current; + for (const UnwrappedLineNode &Node : llvm::drop_begin(Line.Tokens)) { + Current->Next = Node.Tok; + Node.Tok->Previous = Current; Current = Current->Next; Current->Children.clear(); for (const auto &Child : Node.Children) { diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index f652a4e7088f..0172a224335c 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -262,14 +262,48 @@ private: } } - // FIXME: TheLine->Level != 0 might or might not be the right check to do. - // If necessary, change to something smarter. - bool MergeShortFunctions = - Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All || - (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty && - I[1]->First->is(tok::r_brace)) || - (Style.AllowShortFunctionsOnASingleLine & FormatStyle::SFS_InlineOnly && - TheLine->Level != 0); + auto ShouldMergeShortFunctions = + [this, B = AnnotatedLines.begin()]( + SmallVectorImpl<AnnotatedLine *>::const_iterator I) { + if (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All) + return true; + if (Style.AllowShortFunctionsOnASingleLine >= + FormatStyle::SFS_Empty && + I[1]->First->is(tok::r_brace)) + return true; + + if (Style.AllowShortFunctionsOnASingleLine & + FormatStyle::SFS_InlineOnly) { + // Just checking TheLine->Level != 0 is not enough, because it + // provokes treating functions inside indented namespaces as short. + if (Style.isJavaScript() && (*I)->Last->is(TT_FunctionLBrace)) + return true; + + if ((*I)->Level != 0) { + if (I == B) + return false; + + // TODO: Use IndentTracker to avoid loop? + // Find the last line with lower level. + auto J = I - 1; + for (; J != B; --J) + if ((*J)->Level < (*I)->Level) + break; + + // Check if the found line starts a record. + for (const FormatToken *RecordTok = (*J)->Last; RecordTok; + RecordTok = RecordTok->Previous) + if (RecordTok->is(tok::l_brace)) + return RecordTok->is(TT_RecordLBrace); + + return false; + } + } + + return false; + }; + + bool MergeShortFunctions = ShouldMergeShortFunctions(I); if (Style.CompactNamespaces) { if (auto nsToken = TheLine->First->getNamespaceToken()) { @@ -313,7 +347,8 @@ private: } // Try to merge a control statement block with left brace unwrapped if (TheLine->Last->is(tok::l_brace) && TheLine->First != TheLine->Last && - TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { + TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for, + TT_ForEachMacro)) { return Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never ? tryMergeSimpleBlock(I, E, Limit) : 0; @@ -336,7 +371,7 @@ private: : 0; } else if (I[1]->First->is(tok::l_brace) && TheLine->First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, - tok::kw_for)) { + tok::kw_for, TT_ForEachMacro)) { return (Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Always) ? tryMergeSimpleBlock(I, E, Limit) @@ -391,7 +426,7 @@ private: } } - // Try to merge a block with left brace wrapped that wasn't yet covered + // Try to merge a block with left brace unwrapped that wasn't yet covered if (TheLine->Last->is(tok::l_brace)) { const FormatToken *Tok = TheLine->First; bool ShouldMerge = false; @@ -451,7 +486,8 @@ private: ? tryMergeSimpleControlStatement(I, E, Limit) : 0; } - if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while, tok::kw_do)) { + if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while, tok::kw_do, + TT_ForEachMacro)) { return Style.AllowShortLoopsOnASingleLine ? tryMergeSimpleControlStatement(I, E, Limit) : 0; @@ -499,13 +535,14 @@ private: if (!Line.First->is(tok::kw_do) && !Line.First->is(tok::kw_else) && !Line.Last->is(tok::kw_else) && Line.Last->isNot(tok::r_paren)) return 0; - // Only merge do while if do is the only statement on the line. + // Only merge `do while` if `do` is the only statement on the line. if (Line.First->is(tok::kw_do) && !Line.Last->is(tok::kw_do)) return 0; if (1 + I[1]->Last->TotalLength > Limit) return 0; + // Don't merge with loops, ifs, a single semicolon or a line comment. if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for, tok::kw_while, - TT_LineComment)) + TT_ForEachMacro, TT_LineComment)) return 0; // Only inline simple if's (no nested if or else), unless specified if (Style.AllowShortIfStatementsOnASingleLine == @@ -593,8 +630,8 @@ private: } if (Line.First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, tok::kw_do, tok::kw_try, tok::kw___try, tok::kw_catch, - tok::kw___finally, tok::kw_for, tok::r_brace, - Keywords.kw___except)) { + tok::kw___finally, tok::kw_for, TT_ForEachMacro, + tok::r_brace, Keywords.kw___except)) { if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) return 0; if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Empty && @@ -614,12 +651,14 @@ private: I + 2 != E && !I[2]->First->is(tok::r_brace)) return 0; if (!Style.AllowShortLoopsOnASingleLine && - Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) && + Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for, + TT_ForEachMacro) && !Style.BraceWrapping.AfterControlStatement && !I[1]->First->is(tok::r_brace)) return 0; if (!Style.AllowShortLoopsOnASingleLine && - Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) && + Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for, + TT_ForEachMacro) && Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Always && I + 2 != E && !I[2]->First->is(tok::r_brace)) @@ -1060,9 +1099,9 @@ private: FormatDecision LastFormat = Node->State.NextToken->getDecision(); if (LastFormat == FD_Unformatted || LastFormat == FD_Continue) - addNextStateToQueue(Penalty, Node, /*NewLine=*/false, Count, Queue); + addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue); if (LastFormat == FD_Unformatted || LastFormat == FD_Break) - addNextStateToQueue(Penalty, Node, /*NewLine=*/true, Count, Queue); + addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue); } if (Queue.empty()) { @@ -1088,7 +1127,7 @@ private: /// Assume the current state is \p PreviousNode and has been reached with a /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true. void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode, - bool NewLine, unsigned &Count, QueueType &Queue) { + bool NewLine, unsigned *Count, QueueType *Queue) { if (NewLine && !Indenter->canBreak(PreviousNode->State)) return; if (!NewLine && Indenter->mustBreak(PreviousNode->State)) @@ -1101,29 +1140,29 @@ private: Penalty += Indenter->addTokenToState(Node->State, NewLine, true); - Queue.push(QueueItem(OrderedPenalty(Penalty, Count), Node)); - ++Count; + Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node)); + ++(*Count); } /// Applies the best formatting by reconstructing the path in the /// solution space that leads to \c Best. void reconstructPath(LineState &State, StateNode *Best) { - std::deque<StateNode *> Path; + llvm::SmallVector<StateNode *> Path; // We do not need a break before the initial token. while (Best->Previous) { - Path.push_front(Best); + Path.push_back(Best); Best = Best->Previous; } - for (auto I = Path.begin(), E = Path.end(); I != E; ++I) { + for (const auto &Node : llvm::reverse(Path)) { unsigned Penalty = 0; - formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty); - Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false); + formatChildren(State, Node->NewLine, /*DryRun=*/false, Penalty); + Penalty += Indenter->addTokenToState(State, Node->NewLine, false); LLVM_DEBUG({ - printLineState((*I)->Previous->State); - if ((*I)->NewLine) { + printLineState(Node->Previous->State); + if (Node->NewLine) { llvm::dbgs() << "Penalty for placing " - << (*I)->Previous->State.NextToken->Tok.getName() + << Node->Previous->State.NextToken->Tok.getName() << " on a new line: " << Penalty << "\n"; } }); @@ -1162,7 +1201,9 @@ unsigned UnwrappedLineFormatter::format( bool FirstLine = true; for (const AnnotatedLine *Line = Joiner.getNextMergedLine(DryRun, IndentTracker); - Line; Line = NextLine, FirstLine = false) { + Line; PrevPrevLine = PreviousLine, PreviousLine = Line, Line = NextLine, + FirstLine = false) { + assert(Line->First); const AnnotatedLine &TheLine = *Line; unsigned Indent = IndentTracker.getIndent(); @@ -1190,7 +1231,7 @@ unsigned UnwrappedLineFormatter::format( if (ShouldFormat && TheLine.Type != LT_Invalid) { if (!DryRun) { - bool LastLine = Line->First->is(tok::eof); + bool LastLine = TheLine.First->is(tok::eof); formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines, Indent, LastLine ? LastStartColumn : NextStartColumn + Indent); } @@ -1252,8 +1293,6 @@ unsigned UnwrappedLineFormatter::format( } if (!DryRun) markFinalized(TheLine.First); - PrevPrevLine = PreviousLine; - PreviousLine = &TheLine; } PenaltyCache[CacheKey] = Penalty; return Penalty; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index b6e55aab708f..35be2fa3eb62 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -14,6 +14,7 @@ #include "UnwrappedLineParser.h" #include "FormatToken.h" +#include "TokenAnnotator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -32,7 +33,7 @@ public: // Returns the next token in the token stream. virtual FormatToken *getNextToken() = 0; - // Returns the token precedint the token returned by the last call to + // Returns the token preceding the token returned by the last call to // getNextToken() in the token stream, or nullptr if no such token exists. virtual FormatToken *getPreviousToken() = 0; @@ -57,7 +58,7 @@ namespace { class ScopedDeclarationState { public: - ScopedDeclarationState(UnwrappedLine &Line, std::vector<bool> &Stack, + ScopedDeclarationState(UnwrappedLine &Line, llvm::BitVector &Stack, bool MustBeDeclaration) : Line(Line), Stack(Stack) { Line.MustBeDeclaration = MustBeDeclaration; @@ -73,7 +74,7 @@ public: private: UnwrappedLine &Line; - std::vector<bool> &Stack; + llvm::BitVector &Stack; }; static bool isLineComment(const FormatToken &FormatTok) { @@ -246,8 +247,7 @@ public: } FormatToken *getPreviousToken() override { - assert(Position > 0); - return Tokens[Position - 1]; + return Position > 0 ? Tokens[Position - 1] : nullptr; } FormatToken *peekNextToken() override { @@ -316,6 +316,7 @@ void UnwrappedLineParser::reset() { PreprocessorDirectives.clear(); CurrentLines = &Lines; DeclarationScopeStack.clear(); + NestedTooDeep.clear(); PPStack.clear(); Line->FirstStartColumn = FirstStartColumn; } @@ -343,11 +344,9 @@ void UnwrappedLineParser::parse() { pushToken(FormatTok); addUnwrappedLine(); - for (SmallVectorImpl<UnwrappedLine>::iterator I = Lines.begin(), - E = Lines.end(); - I != E; ++I) { - Callback.consumeUnwrappedLine(*I); - } + for (const UnwrappedLine &Line : Lines) + Callback.consumeUnwrappedLine(Line); + Callback.finishRun(); Lines.clear(); while (!PPLevelBranchIndex.empty() && @@ -431,7 +430,47 @@ void UnwrappedLineParser::parseCSharpAttribute() { } while (!eof()); } -void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { +bool UnwrappedLineParser::precededByCommentOrPPDirective() const { + if (!Lines.empty() && Lines.back().InPPDirective) + return true; + + const FormatToken *Previous = Tokens->getPreviousToken(); + return Previous && Previous->is(tok::comment) && + (Previous->IsMultiline || Previous->NewlinesBefore > 0); +} + +bool UnwrappedLineParser::mightFitOnOneLine() const { + const auto ColumnLimit = Style.ColumnLimit; + if (ColumnLimit == 0) + return true; + + if (Lines.empty()) + return true; + + const auto &PreviousLine = Lines.back(); + const auto &Tokens = PreviousLine.Tokens; + assert(!Tokens.empty()); + const auto *LastToken = Tokens.back().Tok; + assert(LastToken); + if (!LastToken->isOneOf(tok::semi, tok::comment)) + return true; + + AnnotatedLine Line(PreviousLine); + assert(Line.Last == LastToken); + + TokenAnnotator Annotator(Style, Keywords); + Annotator.annotate(Line); + Annotator.calculateFormattingInformation(Line); + + return Line.Level * Style.IndentWidth + LastToken->TotalLength <= ColumnLimit; +} + +// Returns true if a simple block, or false otherwise. (A simple block has a +// single statement that fits on a single line.) +bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind) { + const bool IsPrecededByCommentOrPPDirective = + !Style.RemoveBracesLLVM || precededByCommentOrPPDirective(); + unsigned StatementCount = 0; bool SwitchLabelEncountered = false; do { tok::TokenKind kind = FormatTok->Tok.getKind(); @@ -452,11 +491,24 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { if (!FormatTok->is(TT_MacroBlockBegin) && tryToParseBracedList()) continue; parseBlock(); + ++StatementCount; + assert(StatementCount > 0 && "StatementCount overflow!"); addUnwrappedLine(); break; case tok::r_brace: - if (HasOpeningBrace) - return; + if (HasOpeningBrace) { + if (!Style.RemoveBracesLLVM) + return false; + if (FormatTok->isNot(tok::r_brace) || StatementCount != 1 || + IsPrecededByCommentOrPPDirective || + precededByCommentOrPPDirective()) { + return false; + } + const FormatToken *Next = Tokens->peekNextToken(); + if (Next->is(tok::comment) && Next->NewlinesBefore == 0) + return false; + return mightFitOnOneLine(); + } nextToken(); addUnwrappedLine(); break; @@ -496,10 +548,13 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { } LLVM_FALLTHROUGH; default: - parseStructuralElement(!HasOpeningBrace); + parseStructuralElement(IfKind, !HasOpeningBrace); + ++StatementCount; + assert(StatementCount > 0 && "StatementCount overflow!"); break; } } while (!eof()); + return false; } void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { @@ -655,11 +710,13 @@ size_t UnwrappedLineParser::computePPHash() const { return h; } -void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, - bool MunchSemi, - bool UnindentWhitesmithsBraces) { +UnwrappedLineParser::IfStmtKind +UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, + bool MunchSemi, + bool UnindentWhitesmithsBraces) { assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && "'{' or macro block token expected"); + FormatToken *Tok = FormatTok; const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin); FormatTok->setBlockKind(BK_Block); @@ -694,16 +751,28 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, MustBeDeclaration); if (AddLevels > 0u && Style.BreakBeforeBraces != FormatStyle::BS_Whitesmiths) Line->Level += AddLevels; - parseLevel(/*HasOpeningBrace=*/true); + + IfStmtKind IfKind = IfStmtKind::NotIf; + const bool SimpleBlock = parseLevel(/*HasOpeningBrace=*/true, &IfKind); if (eof()) - return; + return IfKind; if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd) : !FormatTok->is(tok::r_brace)) { Line->Level = InitialLevel; FormatTok->setBlockKind(BK_Block); - return; + return IfKind; + } + + if (SimpleBlock && Tok->is(tok::l_brace)) { + assert(FormatTok->is(tok::r_brace)); + const FormatToken *Previous = Tokens->getPreviousToken(); + assert(Previous); + if (Previous->isNot(tok::r_brace) || Previous->Optional) { + Tok->MatchingParen = FormatTok; + FormatTok->MatchingParen = Tok; + } } size_t PPEndHash = computePPHash(); @@ -734,6 +803,8 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, CurrentLines->size() - 1; } } + + return IfKind; } static bool isGoogScope(const UnwrappedLine &Line) { @@ -782,6 +853,8 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style, return Style.BraceWrapping.AfterUnion; if (InitialToken.is(tok::kw_struct)) return Style.BraceWrapping.AfterStruct; + if (InitialToken.is(tok::kw_enum)) + return Style.BraceWrapping.AfterEnum; return false; } @@ -969,8 +1042,7 @@ void UnwrappedLineParser::parsePPDefine() { nextToken(); if (FormatTok->Tok.getKind() == tok::l_paren && - FormatTok->WhitespaceRange.getBegin() == - FormatTok->WhitespaceRange.getEnd()) { + !FormatTok->hasWhitespaceBefore()) { parseParens(); } if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) @@ -1186,7 +1258,8 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() { return addUnwrappedLine(); } -void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { +void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, + bool IsTopLevel) { if (Style.Language == FormatStyle::LK_TableGen && FormatTok->is(tok::pp_include)) { nextToken(); @@ -1229,7 +1302,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { if (Style.isJavaScript() && Line->MustBeDeclaration) // field/method declaration. break; - parseIfThenElse(); + parseIfThenElse(IfKind); return; case tok::kw_for: case tok::kw_while: @@ -1523,8 +1596,16 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { // structural element. // FIXME: Figure out cases where this is not true, and add projections // for them (the one we know is missing are lambdas). - if (Style.BraceWrapping.AfterFunction) + if (Style.Language == FormatStyle::LK_Java && + Line->Tokens.front().Tok->is(Keywords.kw_synchronized)) { + // If necessary, we could set the type to something different than + // TT_FunctionLBrace. + if (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always) + addUnwrappedLine(); + } else if (Style.BraceWrapping.AfterFunction) { addUnwrappedLine(); + } FormatTok->setType(TT_FunctionLBrace); parseBlock(); addUnwrappedLine(); @@ -1601,6 +1682,8 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { // See if the following token should start a new unwrapped line. StringRef Text = FormatTok->TokenText; + + FormatToken *PreviousToken = FormatTok; nextToken(); // JS doesn't have macros, and within classes colons indicate fields, not @@ -1629,6 +1712,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) && tokenCanStartNewLine(*FormatTok) && Text == Text.upper()) { + PreviousToken->setType(TT_FunctionLikeOrFreestandingMacro); addUnwrappedLine(); return; } @@ -1772,6 +1856,7 @@ bool UnwrappedLineParser::tryToParseLambda() { return false; bool SeenArrow = false; + bool InTemplateParameterList = false; while (FormatTok->isNot(tok::l_brace)) { if (FormatTok->isSimpleTypeSpecifier()) { @@ -1784,6 +1869,17 @@ bool UnwrappedLineParser::tryToParseLambda() { case tok::l_paren: parseParens(); break; + case tok::l_square: + parseSquare(); + break; + case tok::kw_class: + case tok::kw_template: + case tok::kw_typename: + assert(FormatTok->Previous); + if (FormatTok->Previous->is(tok::less)) + InTemplateParameterList = true; + nextToken(); + break; case tok::amp: case tok::star: case tok::kw_const: @@ -1793,11 +1889,8 @@ bool UnwrappedLineParser::tryToParseLambda() { case tok::identifier: case tok::numeric_constant: case tok::coloncolon: - case tok::kw_class: case tok::kw_mutable: case tok::kw_noexcept: - case tok::kw_template: - case tok::kw_typename: nextToken(); break; // Specialization of a template with an integer parameter can contain @@ -1834,7 +1927,7 @@ bool UnwrappedLineParser::tryToParseLambda() { case tok::ellipsis: case tok::kw_true: case tok::kw_false: - if (SeenArrow) { + if (SeenArrow || InTemplateParameterList) { nextToken(); break; } @@ -2128,7 +2221,39 @@ void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) { } while (!eof()); } -void UnwrappedLineParser::parseIfThenElse() { +void UnwrappedLineParser::keepAncestorBraces() { + if (!Style.RemoveBracesLLVM) + return; + + const int MaxNestingLevels = 2; + const int Size = NestedTooDeep.size(); + if (Size >= MaxNestingLevels) + NestedTooDeep[Size - MaxNestingLevels] = true; + NestedTooDeep.push_back(false); +} + +static void markOptionalBraces(FormatToken *LeftBrace) { + if (!LeftBrace) + return; + + assert(LeftBrace->is(tok::l_brace)); + + FormatToken *RightBrace = LeftBrace->MatchingParen; + if (!RightBrace) { + assert(!LeftBrace->Optional); + return; + } + + assert(RightBrace->is(tok::r_brace)); + assert(RightBrace->MatchingParen == LeftBrace); + assert(LeftBrace->Optional == RightBrace->Optional); + + LeftBrace->Optional = true; + RightBrace->Optional = true; +} + +FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind, + bool KeepBraces) { auto HandleAttributes = [this]() { // Handle AttributeMacro, e.g. `if (x) UNLIKELY`. if (FormatTok->is(TT_AttributeMacro)) @@ -2145,10 +2270,17 @@ void UnwrappedLineParser::parseIfThenElse() { if (FormatTok->Tok.is(tok::l_paren)) parseParens(); HandleAttributes(); + bool NeedsUnwrappedLine = false; + keepAncestorBraces(); + + FormatToken *IfLeftBrace = nullptr; + IfStmtKind IfBlockKind = IfStmtKind::NotIf; + if (FormatTok->Tok.is(tok::l_brace)) { + IfLeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(); + IfBlockKind = parseBlock(); if (Style.BraceWrapping.BeforeElse) addUnwrappedLine(); else @@ -2159,22 +2291,48 @@ void UnwrappedLineParser::parseIfThenElse() { parseStructuralElement(); --Line->Level; } + + bool KeepIfBraces = false; + if (Style.RemoveBracesLLVM) { + assert(!NestedTooDeep.empty()); + KeepIfBraces = (IfLeftBrace && !IfLeftBrace->MatchingParen) || + NestedTooDeep.back() || IfBlockKind == IfStmtKind::IfOnly || + IfBlockKind == IfStmtKind::IfElseIf; + } + + FormatToken *ElseLeftBrace = nullptr; + IfStmtKind Kind = IfStmtKind::IfOnly; + if (FormatTok->Tok.is(tok::kw_else)) { + if (Style.RemoveBracesLLVM) { + NestedTooDeep.back() = false; + Kind = IfStmtKind::IfElse; + } nextToken(); HandleAttributes(); if (FormatTok->Tok.is(tok::l_brace)) { + ElseLeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(); + if (parseBlock() == IfStmtKind::IfOnly) + Kind = IfStmtKind::IfElseIf; addUnwrappedLine(); } else if (FormatTok->Tok.is(tok::kw_if)) { FormatToken *Previous = Tokens->getPreviousToken(); - bool PrecededByComment = Previous && Previous->is(tok::comment); - if (PrecededByComment) { + const bool IsPrecededByComment = Previous && Previous->is(tok::comment); + if (IsPrecededByComment) { addUnwrappedLine(); ++Line->Level; } - parseIfThenElse(); - if (PrecededByComment) + bool TooDeep = true; + if (Style.RemoveBracesLLVM) { + Kind = IfStmtKind::IfElseIf; + TooDeep = NestedTooDeep.pop_back_val(); + } + ElseLeftBrace = + parseIfThenElse(/*IfKind=*/nullptr, KeepBraces || KeepIfBraces); + if (Style.RemoveBracesLLVM) + NestedTooDeep.push_back(TooDeep); + if (IsPrecededByComment) --Line->Level; } else { addUnwrappedLine(); @@ -2184,9 +2342,40 @@ void UnwrappedLineParser::parseIfThenElse() { addUnwrappedLine(); --Line->Level; } - } else if (NeedsUnwrappedLine) { - addUnwrappedLine(); + } else { + if (Style.RemoveBracesLLVM) + KeepIfBraces = KeepIfBraces || IfBlockKind == IfStmtKind::IfElse; + if (NeedsUnwrappedLine) + addUnwrappedLine(); + } + + if (!Style.RemoveBracesLLVM) + return nullptr; + + assert(!NestedTooDeep.empty()); + const bool KeepElseBraces = + (ElseLeftBrace && !ElseLeftBrace->MatchingParen) || NestedTooDeep.back(); + + NestedTooDeep.pop_back(); + + if (!KeepBraces && !KeepIfBraces && !KeepElseBraces) { + markOptionalBraces(IfLeftBrace); + markOptionalBraces(ElseLeftBrace); + } else if (IfLeftBrace) { + FormatToken *IfRightBrace = IfLeftBrace->MatchingParen; + if (IfRightBrace) { + assert(IfRightBrace->MatchingParen == IfLeftBrace); + assert(!IfLeftBrace->Optional); + assert(!IfRightBrace->Optional); + IfLeftBrace->MatchingParen = nullptr; + IfRightBrace->MatchingParen = nullptr; + } } + + if (IfKind) + *IfKind = Kind; + + return IfLeftBrace; } void UnwrappedLineParser::parseTryCatch() { @@ -2224,6 +2413,9 @@ void UnwrappedLineParser::parseTryCatch() { if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) { parseParens(); } + + keepAncestorBraces(); + if (FormatTok->is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(); @@ -2241,7 +2433,7 @@ void UnwrappedLineParser::parseTryCatch() { parseStructuralElement(); --Line->Level; } - while (1) { + while (true) { if (FormatTok->is(tok::at)) nextToken(); if (!(FormatTok->isOneOf(tok::kw_catch, Keywords.kw___except, @@ -2257,8 +2449,11 @@ void UnwrappedLineParser::parseTryCatch() { parseParens(); continue; } - if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof)) + if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof)) { + if (Style.RemoveBracesLLVM) + NestedTooDeep.pop_back(); return; + } nextToken(); } NeedsUnwrappedLine = false; @@ -2269,6 +2464,10 @@ void UnwrappedLineParser::parseTryCatch() { else NeedsUnwrappedLine = true; } + + if (Style.RemoveBracesLLVM) + NestedTooDeep.pop_back(); + if (NeedsUnwrappedLine) addUnwrappedLine(); } @@ -2283,7 +2482,8 @@ void UnwrappedLineParser::parseNamespace() { parseParens(); } else { while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline, - tok::l_square, tok::period)) { + tok::l_square, tok::period) || + (Style.isCSharp() && FormatTok->is(tok::kw_union))) { if (FormatTok->is(tok::l_square)) parseSquare(); else @@ -2375,9 +2575,18 @@ void UnwrappedLineParser::parseForOrWhileLoop() { nextToken(); if (FormatTok->Tok.is(tok::l_paren)) parseParens(); + + keepAncestorBraces(); + if (FormatTok->Tok.is(tok::l_brace)) { + FormatToken *LeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(); + if (Style.RemoveBracesLLVM) { + assert(!NestedTooDeep.empty()); + if (!NestedTooDeep.back()) + markOptionalBraces(LeftBrace); + } addUnwrappedLine(); } else { addUnwrappedLine(); @@ -2385,11 +2594,17 @@ void UnwrappedLineParser::parseForOrWhileLoop() { parseStructuralElement(); --Line->Level; } + + if (Style.RemoveBracesLLVM) + NestedTooDeep.pop_back(); } void UnwrappedLineParser::parseDoWhile() { assert(FormatTok->Tok.is(tok::kw_do) && "'do' expected"); nextToken(); + + keepAncestorBraces(); + if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(); @@ -2402,6 +2617,9 @@ void UnwrappedLineParser::parseDoWhile() { --Line->Level; } + if (Style.RemoveBracesLLVM) + NestedTooDeep.pop_back(); + // FIXME: Add error handling. if (!FormatTok->Tok.is(tok::kw_while)) { addUnwrappedLine(); @@ -2438,7 +2656,7 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { addUnwrappedLine(); if (!Style.IndentCaseBlocks && Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { - Line->Level++; + ++Line->Level; } } parseStructuralElement(); @@ -2471,6 +2689,9 @@ void UnwrappedLineParser::parseSwitch() { nextToken(); if (FormatTok->Tok.is(tok::l_paren)) parseParens(); + + keepAncestorBraces(); + if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(); @@ -2481,6 +2702,9 @@ void UnwrappedLineParser::parseSwitch() { parseStructuralElement(); --Line->Level; } + + if (Style.RemoveBracesLLVM) + NestedTooDeep.pop_back(); } void UnwrappedLineParser::parseAccessSpecifier() { @@ -2597,7 +2821,7 @@ void UnwrappedLineParser::parseRequires() { if (FormatTok->Previous && FormatTok->Previous->is(tok::greater)) { addUnwrappedLine(); if (Style.IndentRequires) { - Line->Level++; + ++Line->Level; } } nextToken(); @@ -2606,12 +2830,12 @@ void UnwrappedLineParser::parseRequires() { } bool UnwrappedLineParser::parseEnum() { + const FormatToken &InitialToken = *FormatTok; + // Won't be 'enum' for NS_ENUMs. if (FormatTok->Tok.is(tok::kw_enum)) nextToken(); - const FormatToken &InitialToken = *FormatTok; - // In TypeScript, "enum" can also be used as property name, e.g. in interface // declarations. An "enum" keyword followed by a colon would be a syntax // error and thus assume it is just an identifier. @@ -2645,6 +2869,7 @@ bool UnwrappedLineParser::parseEnum() { // Just a declaration or something is wrong. if (FormatTok->isNot(tok::l_brace)) return true; + FormatTok->setType(TT_RecordLBrace); FormatTok->setBlockKind(BK_Block); if (Style.Language == FormatStyle::LK_Java) { @@ -2864,6 +3089,15 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { if (!tryToParseBracedList()) break; } + if (FormatTok->is(tok::l_square)) { + FormatToken *Previous = FormatTok->Previous; + if (!Previous || Previous->isNot(tok::r_paren)) { + // Don't try parsing a lambda if we had a closing parenthesis before, + // it was probably a pointer to an array: int (*)[]. + if (!tryToParseLambda()) + break; + } + } if (FormatTok->Tok.is(tok::semi)) return; if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) { @@ -2876,6 +3110,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { } } if (FormatTok->Tok.is(tok::l_brace)) { + FormatTok->setType(TT_RecordLBrace); if (ParseAsExpr) { parseChildBlock(); } else { @@ -3264,10 +3499,7 @@ continuesLineCommentSection(const FormatToken &FormatTok, void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) { bool JustComments = Line->Tokens.empty(); - for (SmallVectorImpl<FormatToken *>::const_iterator - I = CommentsBeforeNextToken.begin(), - E = CommentsBeforeNextToken.end(); - I != E; ++I) { + for (FormatToken *Tok : CommentsBeforeNextToken) { // Line comments that belong to the same line comment section are put on the // same line since later we might want to reflow content between them. // Additional fine-grained breaking of line comment sections is controlled @@ -3276,11 +3508,11 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) { // // FIXME: Consider putting separate line comment sections as children to the // unwrapped line instead. - (*I)->ContinuesLineCommentSection = - continuesLineCommentSection(**I, *Line, CommentPragmasRegex); - if (isOnNewLine(**I) && JustComments && !(*I)->ContinuesLineCommentSection) + Tok->ContinuesLineCommentSection = + continuesLineCommentSection(*Tok, *Line, CommentPragmasRegex); + if (isOnNewLine(*Tok) && JustComments && !Tok->ContinuesLineCommentSection) addUnwrappedLine(); - pushToken(*I); + pushToken(Tok); } if (NewlineBeforeNext && JustComments) addUnwrappedLine(); diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 0c79723d50fc..3f64d57c7bff 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -18,6 +18,7 @@ #include "FormatToken.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Format/Format.h" +#include "llvm/ADT/BitVector.h" #include "llvm/Support/Regex.h" #include <stack> #include <vector> @@ -81,12 +82,21 @@ public: void parse(); private: + enum class IfStmtKind { + NotIf, // Not an if statement. + IfOnly, // An if statement without the else clause. + IfElse, // An if statement followed by else but not else if. + IfElseIf // An if statement followed by else if. + }; + void reset(); void parseFile(); - void parseLevel(bool HasOpeningBrace); - void parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u, - bool MunchSemi = true, - bool UnindentWhitesmithsBraces = false); + bool precededByCommentOrPPDirective() const; + bool mightFitOnOneLine() const; + bool parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind = nullptr); + IfStmtKind parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u, + bool MunchSemi = true, + bool UnindentWhitesmithsBraces = false); void parseChildBlock(); void parsePPDirective(); void parsePPDefine(); @@ -96,13 +106,15 @@ private: void parsePPEndIf(); void parsePPUnknown(); void readTokenWithJavaScriptASI(); - void parseStructuralElement(bool IsTopLevel = false); + void parseStructuralElement(IfStmtKind *IfKind = nullptr, + bool IsTopLevel = false); bool tryToParseBracedList(); bool parseBracedList(bool ContinueOnSemicolons = false, bool IsEnum = false, tok::TokenKind ClosingBraceKind = tok::r_brace); void parseParens(); void parseSquare(bool LambdaIntroducer = false); - void parseIfThenElse(); + void keepAncestorBraces(); + FormatToken *parseIfThenElse(IfStmtKind *IfKind, bool KeepBraces = false); void parseTryCatch(); void parseForOrWhileLoop(); void parseDoWhile(); @@ -220,7 +232,7 @@ private: // We store for each line whether it must be a declaration depending on // whether we are in a compound statement or not. - std::vector<bool> DeclarationScopeStack; + llvm::BitVector DeclarationScopeStack; const FormatStyle &Style; const AdditionalKeywords &Keywords; @@ -235,6 +247,10 @@ private: // owned outside of and handed into the UnwrappedLineParser. ArrayRef<FormatToken *> AllTokens; + // Keeps a stack of the states of nested control statements (true if the + // statement contains more than some predefined number of nested statements). + SmallVector<bool, 8> NestedTooDeep; + // Represents preprocessor branch type, so we can find matching // #if/#else/#endif directives. enum PPBranchKind { diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 96a66da0f82b..0d2e507ac587 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -74,6 +74,12 @@ WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) { return Replaces.add(Replacement); } +bool WhitespaceManager::inputUsesCRLF(StringRef Text, bool DefaultToCRLF) { + size_t LF = Text.count('\n'); + size_t CR = Text.count('\r') * 2; + return LF == CR ? DefaultToCRLF : CR > LF; +} + void WhitespaceManager::replaceWhitespaceInToken( const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, @@ -304,7 +310,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, unsigned PreviousNonComment = i - 1; while (PreviousNonComment > Start && Changes[PreviousNonComment].Tok->is(tok::comment)) - PreviousNonComment--; + --PreviousNonComment; if (i != Start && Changes[i].indentAndNestingLevel() > Changes[PreviousNonComment].indentAndNestingLevel()) ScopeStack.push_back(i); @@ -362,6 +368,13 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, Changes[i].Tok->Previous->is(TT_ConditionalExpr)) return true; + // Continued braced list. + if (ScopeStart > Start + 1 && + Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && + Changes[ScopeStart - 1].Tok->is(tok::l_brace) && + Changes[i].Tok->isNot(tok::r_brace)) + return true; + return false; }; @@ -718,6 +731,11 @@ void WhitespaceManager::alignConsecutiveAssignments() { if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0) return false; + // Do not align operator= overloads. + FormatToken *Previous = C.Tok->getPreviousNonComment(); + if (Previous && Previous->is(tok::kw_operator)) + return false; + return C.Tok->is(tok::equal); }, Changes, /*StartAt=*/0, Style.AlignConsecutiveAssignments); @@ -1160,7 +1178,7 @@ WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start, NextNonComment = NextNonComment->getNextNonComment(); auto j = i; while (Changes[j].Tok != NextNonComment && j < End) - j++; + ++j; if (j < End && Changes[j].NewlinesBefore == 0 && Changes[j].Tok->isNot(tok::r_brace)) { Changes[j].NewlinesBefore = 1; diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h index 029f4159b748..42f958f68ba6 100644 --- a/clang/lib/Format/WhitespaceManager.h +++ b/clang/lib/Format/WhitespaceManager.h @@ -45,6 +45,9 @@ public: bool useCRLF() const { return UseCRLF; } + /// Infers whether the input is using CRLF. + static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF); + /// Replaces the whitespace in front of \p Tok. Only call once for /// each \c AnnotatedToken. /// @@ -242,7 +245,7 @@ private: /// as described by \p CellDescs. void alignArrayInitializersRightJustified(CellDescriptions &&CellDescs); - /// Align Array Initializers being careful to leftt justify the columns + /// Align Array Initializers being careful to left justify the columns /// as described by \p CellDescs. void alignArrayInitializersLeftJustified(CellDescriptions &&CellDescs); diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 52589677ca28..5f587cc1c023 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -817,7 +817,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( AST->Reader = new ASTReader( PP, *AST->ModuleCache, AST->Ctx.get(), PCHContainerRdr, {}, /*isysroot=*/"", - /*DisableValidation=*/disableValid, AllowASTWithCompilerErrors); + /*DisableValidationKind=*/disableValid, AllowASTWithCompilerErrors); AST->Reader->setListener(std::make_unique<ASTInfoCollector>( *AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts, @@ -1922,9 +1922,10 @@ namespace { void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates, - SourceLocation OpenParLoc) override { + SourceLocation OpenParLoc, + bool Braced) override { Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates, - OpenParLoc); + OpenParLoc, Braced); } CodeCompletionAllocator &getAllocator() override { diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 31e7ea3d243d..2465a7e2453b 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -37,6 +37,7 @@ #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/InMemoryModuleCache.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/BuryPointer.h" #include "llvm/Support/CrashRecoveryContext.h" @@ -996,6 +997,11 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // DesiredStackSpace available. noteBottomOfStack(); + auto FinishDiagnosticClient = llvm::make_scope_exit([&]() { + // Notify the diagnostic client that all files were processed. + getDiagnosticClient().finish(); + }); + raw_ostream &OS = getVerboseOutputStream(); if (!Act.PrepareToExecute(*this)) @@ -1034,9 +1040,6 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { } } - // Notify the diagnostic client that all files were processed. - getDiagnostics().getClient()->finish(); - if (getDiagnosticOpts().ShowCarets) { // We can have multiple diagnostics sharing one diagnostic client. // Get the total number of warnings/errors from the client. @@ -1414,7 +1417,7 @@ static bool compileModuleAndReadASTBehindLock( StringRef Dir = llvm::sys::path::parent_path(ModuleFileName); llvm::sys::fs::create_directories(Dir); - while (1) { + while (true) { llvm::LockFileManager Locked(ModuleFileName); switch (Locked) { case llvm::LockFileManager::LFS_Error: diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b71addd84bfd..7f1ce3da7e7e 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -438,7 +438,7 @@ static T extractMaskValue(T KeyPath) { }(EXTRACTOR(KEYPATH)); \ } -static const StringRef GetInputKindName(InputKind IK); +static StringRef GetInputKindName(InputKind IK); static bool FixupInvocation(CompilerInvocation &Invocation, DiagnosticsEngine &Diags, const ArgList &Args, @@ -1814,6 +1814,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; } + if (Opts.PrepareForLTO && Args.hasArg(OPT_mibt_seal)) + Opts.IBTSeal = 1; + for (auto *A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_builtin_bitcode)) { CodeGenOptions::BitcodeFileToLink F; @@ -2405,6 +2408,7 @@ static const auto &getFrontendActionTable() { {frontend::EmitCodeGenOnly, OPT_emit_codegen_only}, {frontend::EmitCodeGenOnly, OPT_emit_codegen_only}, {frontend::EmitObj, OPT_emit_obj}, + {frontend::ExtractAPI, OPT_extract_api}, {frontend::FixIt, OPT_fixit_EQ}, {frontend::FixIt, OPT_fixit}, @@ -3291,7 +3295,7 @@ static bool IsInputCompatibleWithStandard(InputKind IK, } /// Get language name for given input kind. -static const StringRef GetInputKindName(InputKind IK) { +static StringRef GetInputKindName(InputKind IK) { switch (IK.getLanguage()) { case Language::C: return "C"; @@ -4144,6 +4148,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { case frontend::EmitLLVMOnly: case frontend::EmitCodeGenOnly: case frontend::EmitObj: + case frontend::ExtractAPI: case frontend::FixIt: case frontend::GenerateModule: case frontend::GenerateModuleInterface: diff --git a/clang/lib/Frontend/ExtractAPIConsumer.cpp b/clang/lib/Frontend/ExtractAPIConsumer.cpp new file mode 100644 index 000000000000..cdf67f3c327a --- /dev/null +++ b/clang/lib/Frontend/ExtractAPIConsumer.cpp @@ -0,0 +1,32 @@ +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" + +using namespace clang; + +namespace { +class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> { +public: + bool VisitNamedDecl(NamedDecl *Decl) { + llvm::outs() << Decl->getName() << "\n"; + return true; + } +}; + +class ExtractAPIConsumer : public ASTConsumer { +public: + void HandleTranslationUnit(ASTContext &Context) override { + Visitor.TraverseDecl(Context.getTranslationUnitDecl()); + } + +private: + ExtractAPIVisitor Visitor; +}; +} // namespace + +std::unique_ptr<ASTConsumer> +ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { + return std::make_unique<ExtractAPIConsumer>(); +} diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index fb8132a5e40a..ad2e6039477f 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -8,9 +8,10 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/AST/ASTConsumer.h" +#include "clang/AST/Decl.h" #include "clang/Basic/FileManager.h" -#include "clang/Basic/TargetInfo.h" #include "clang/Basic/LangStandard.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -23,6 +24,7 @@ #include "clang/Sema/TemplateInstCallback.h" #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTWriter.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -310,9 +312,8 @@ bool GenerateHeaderModuleAction::BeginSourceFileAction( auto &HS = CI.getPreprocessor().getHeaderSearchInfo(); SmallVector<Module::Header, 16> Headers; for (StringRef Name : ModuleHeaders) { - const DirectoryLookup *CurDir = nullptr; Optional<FileEntryRef> FE = HS.LookupFile( - Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, None, + Name, SourceLocation(), /*Angled*/ false, nullptr, nullptr, None, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (!FE) { CI.getDiagnostics().Report(diag::err_module_header_file_not_found) @@ -481,25 +482,92 @@ private: Out << "---" << YAML << "\n"; } + static void printEntryName(const Sema &TheSema, const Decl *Entity, + llvm::raw_string_ostream &OS) { + auto *NamedTemplate = cast<NamedDecl>(Entity); + + PrintingPolicy Policy = TheSema.Context.getPrintingPolicy(); + // FIXME: Also ask for FullyQualifiedNames? + Policy.SuppressDefaultTemplateArgs = false; + NamedTemplate->getNameForDiagnostic(OS, Policy, true); + + if (!OS.str().empty()) + return; + + Decl *Ctx = Decl::castFromDeclContext(NamedTemplate->getDeclContext()); + NamedDecl *NamedCtx = dyn_cast_or_null<NamedDecl>(Ctx); + + if (const auto *Decl = dyn_cast<TagDecl>(NamedTemplate)) { + if (const auto *R = dyn_cast<RecordDecl>(Decl)) { + if (R->isLambda()) { + OS << "lambda at "; + Decl->getLocation().print(OS, TheSema.getSourceManager()); + return; + } + } + OS << "unnamed " << Decl->getKindName(); + return; + } + + if (const auto *Decl = dyn_cast<ParmVarDecl>(NamedTemplate)) { + OS << "unnamed function parameter " << Decl->getFunctionScopeIndex() + << " "; + if (Decl->getFunctionScopeDepth() > 0) + OS << "(at depth " << Decl->getFunctionScopeDepth() << ") "; + OS << "of "; + NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true); + return; + } + + if (const auto *Decl = dyn_cast<TemplateTypeParmDecl>(NamedTemplate)) { + if (const Type *Ty = Decl->getTypeForDecl()) { + if (const auto *TTPT = dyn_cast_or_null<TemplateTypeParmType>(Ty)) { + OS << "unnamed template type parameter " << TTPT->getIndex() << " "; + if (TTPT->getDepth() > 0) + OS << "(at depth " << TTPT->getDepth() << ") "; + OS << "of "; + NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true); + return; + } + } + } + + if (const auto *Decl = dyn_cast<NonTypeTemplateParmDecl>(NamedTemplate)) { + OS << "unnamed template non-type parameter " << Decl->getIndex() << " "; + if (Decl->getDepth() > 0) + OS << "(at depth " << Decl->getDepth() << ") "; + OS << "of "; + NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true); + return; + } + + if (const auto *Decl = dyn_cast<TemplateTemplateParmDecl>(NamedTemplate)) { + OS << "unnamed template template parameter " << Decl->getIndex() << " "; + if (Decl->getDepth() > 0) + OS << "(at depth " << Decl->getDepth() << ") "; + OS << "of "; + NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true); + return; + } + + llvm_unreachable("Failed to retrieve a name for this entry!"); + OS << "unnamed identifier"; + } + template <bool BeginInstantiation> static TemplightEntry getTemplightEntry(const Sema &TheSema, const CodeSynthesisContext &Inst) { TemplightEntry Entry; Entry.Kind = toString(Inst.Kind); Entry.Event = BeginInstantiation ? "Begin" : "End"; - if (auto *NamedTemplate = dyn_cast_or_null<NamedDecl>(Inst.Entity)) { - llvm::raw_string_ostream OS(Entry.Name); - PrintingPolicy Policy = TheSema.Context.getPrintingPolicy(); - // FIXME: Also ask for FullyQualifiedNames? - Policy.SuppressDefaultTemplateArgs = false; - NamedTemplate->getNameForDiagnostic(OS, Policy, true); - const PresumedLoc DefLoc = + llvm::raw_string_ostream OS(Entry.Name); + printEntryName(TheSema, Inst.Entity, OS); + const PresumedLoc DefLoc = TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation()); - if(!DefLoc.isInvalid()) - Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" + - std::to_string(DefLoc.getLine()) + ":" + - std::to_string(DefLoc.getColumn()); - } + if (!DefLoc.isInvalid()) + Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" + + std::to_string(DefLoc.getLine()) + ":" + + std::to_string(DefLoc.getColumn()); const PresumedLoc PoiLoc = TheSema.getSourceManager().getPresumedLoc(Inst.PointOfInstantiation); if (!PoiLoc.isInvalid()) { diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 629f99110661..a9023a7a1171 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -194,7 +194,7 @@ static void DefineType(const Twine &MacroName, TargetInfo::IntType Ty, Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty)); } -static void DefineTypeWidth(StringRef MacroName, TargetInfo::IntType Ty, +static void DefineTypeWidth(const Twine &MacroName, TargetInfo::IntType Ty, const TargetInfo &TI, MacroBuilder &Builder) { Builder.defineMacro(MacroName, Twine(TI.getTypeWidth(Ty))); } @@ -205,6 +205,16 @@ static void DefineTypeSizeof(StringRef MacroName, unsigned BitWidth, Twine(BitWidth / TI.getCharWidth())); } +// This will generate a macro based on the prefix with `_MAX__` as the suffix +// for the max value representable for the type, and a macro with a `_WIDTH__` +// suffix for the width of the type. +static void DefineTypeSizeAndWidth(const Twine &Prefix, TargetInfo::IntType Ty, + const TargetInfo &TI, + MacroBuilder &Builder) { + DefineTypeSize(Prefix + "_MAX__", Ty, TI, Builder); + DefineTypeWidth(Prefix + "_WIDTH__", Ty, TI, Builder); +} + static void DefineExactWidthIntType(TargetInfo::IntType Ty, const TargetInfo &TI, MacroBuilder &Builder) { @@ -241,6 +251,8 @@ static void DefineExactWidthIntTypeSize(TargetInfo::IntType Ty, if (TypeWidth == 64) Ty = IsSigned ? TI.getInt64Type() : TI.getUInt64Type(); + // We don't need to define a _WIDTH macro for the exact-width types because + // we already know the width. const char *Prefix = IsSigned ? "__INT" : "__UINT"; DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder); } @@ -254,7 +266,12 @@ static void DefineLeastWidthIntType(unsigned TypeWidth, bool IsSigned, const char *Prefix = IsSigned ? "__INT_LEAST" : "__UINT_LEAST"; DefineType(Prefix + Twine(TypeWidth) + "_TYPE__", Ty, Builder); - DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder); + // We only want the *_WIDTH macro for the signed types to avoid too many + // predefined macros (the unsigned width and the signed width are identical.) + if (IsSigned) + DefineTypeSizeAndWidth(Prefix + Twine(TypeWidth), Ty, TI, Builder); + else + DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder); DefineFmt(Prefix + Twine(TypeWidth), Ty, TI, Builder); } @@ -268,8 +285,12 @@ static void DefineFastIntType(unsigned TypeWidth, bool IsSigned, const char *Prefix = IsSigned ? "__INT_FAST" : "__UINT_FAST"; DefineType(Prefix + Twine(TypeWidth) + "_TYPE__", Ty, Builder); - DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder); - + // We only want the *_WIDTH macro for the signed types to avoid too many + // predefined macros (the unsigned width and the signed width are identical.) + if (IsSigned) + DefineTypeSizeAndWidth(Prefix + Twine(TypeWidth), Ty, TI, Builder); + else + DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder); DefineFmt(Prefix + Twine(TypeWidth), Ty, TI, Builder); } @@ -887,20 +908,26 @@ static void InitializePredefinedMacros(const TargetInfo &TI, assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far"); Builder.defineMacro("__CHAR_BIT__", Twine(TI.getCharWidth())); + Builder.defineMacro("__BOOL_WIDTH__", Twine(TI.getBoolWidth())); + Builder.defineMacro("__SHRT_WIDTH__", Twine(TI.getShortWidth())); + Builder.defineMacro("__INT_WIDTH__", Twine(TI.getIntWidth())); + Builder.defineMacro("__LONG_WIDTH__", Twine(TI.getLongWidth())); + Builder.defineMacro("__LLONG_WIDTH__", Twine(TI.getLongLongWidth())); + DefineTypeSize("__SCHAR_MAX__", TargetInfo::SignedChar, TI, Builder); DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder); DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder); DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder); DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder); - DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder); - DefineTypeSize("__WINT_MAX__", TI.getWIntType(), TI, Builder); - DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder); - DefineTypeSize("__SIZE_MAX__", TI.getSizeType(), TI, Builder); + DefineTypeSizeAndWidth("__WCHAR", TI.getWCharType(), TI, Builder); + DefineTypeSizeAndWidth("__WINT", TI.getWIntType(), TI, Builder); + DefineTypeSizeAndWidth("__INTMAX", TI.getIntMaxType(), TI, Builder); + DefineTypeSizeAndWidth("__SIZE", TI.getSizeType(), TI, Builder); - DefineTypeSize("__UINTMAX_MAX__", TI.getUIntMaxType(), TI, Builder); - DefineTypeSize("__PTRDIFF_MAX__", TI.getPtrDiffType(0), TI, Builder); - DefineTypeSize("__INTPTR_MAX__", TI.getIntPtrType(), TI, Builder); - DefineTypeSize("__UINTPTR_MAX__", TI.getUIntPtrType(), TI, Builder); + DefineTypeSizeAndWidth("__UINTMAX", TI.getUIntMaxType(), TI, Builder); + DefineTypeSizeAndWidth("__PTRDIFF", TI.getPtrDiffType(0), TI, Builder); + DefineTypeSizeAndWidth("__INTPTR", TI.getIntPtrType(), TI, Builder); + DefineTypeSizeAndWidth("__UINTPTR", TI.getUIntPtrType(), TI, Builder); DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder); DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder); @@ -929,29 +956,29 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineFmt("__UINTMAX", TI.getUIntMaxType(), TI, Builder); Builder.defineMacro("__UINTMAX_C_SUFFIX__", TI.getTypeConstantSuffix(TI.getUIntMaxType())); - DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Builder); DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Builder); DefineFmt("__PTRDIFF", TI.getPtrDiffType(0), TI, Builder); - DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Builder); DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Builder); DefineFmt("__INTPTR", TI.getIntPtrType(), TI, Builder); - DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Builder); DefineType("__SIZE_TYPE__", TI.getSizeType(), Builder); DefineFmt("__SIZE", TI.getSizeType(), TI, Builder); - DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Builder); DefineType("__WCHAR_TYPE__", TI.getWCharType(), Builder); - DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Builder); DefineType("__WINT_TYPE__", TI.getWIntType(), Builder); - DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Builder); - DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Builder); - DefineTypeSize("__SIG_ATOMIC_MAX__", TI.getSigAtomicType(), TI, Builder); + DefineTypeSizeAndWidth("__SIG_ATOMIC", TI.getSigAtomicType(), TI, Builder); DefineType("__CHAR16_TYPE__", TI.getChar16Type(), Builder); DefineType("__CHAR32_TYPE__", TI.getChar32Type(), Builder); - DefineTypeWidth("__UINTMAX_WIDTH__", TI.getUIntMaxType(), TI, Builder); DefineType("__UINTPTR_TYPE__", TI.getUIntPtrType(), Builder); DefineFmt("__UINTPTR", TI.getUIntPtrType(), TI, Builder); - DefineTypeWidth("__UINTPTR_WIDTH__", TI.getUIntPtrType(), TI, Builder); + + // The C standard requires the width of uintptr_t and intptr_t to be the same, + // per 7.20.2.4p1. Same for intmax_t and uintmax_t, per 7.20.2.5p1. + assert(TI.getTypeWidth(TI.getUIntPtrType()) == + TI.getTypeWidth(TI.getIntPtrType()) && + "uintptr_t and intptr_t have different widths?"); + assert(TI.getTypeWidth(TI.getUIntMaxType()) == + TI.getTypeWidth(TI.getIntMaxType()) && + "uintmax_t and intmax_t have different widths?"); if (TI.hasFloat16Type()) DefineFloatMacros(Builder, "FLT16", &TI.getHalfFormat(), "F16"); @@ -1039,6 +1066,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__USER_LABEL_PREFIX__", TI.getUserLabelPrefix()); + if (!LangOpts.MathErrno) + Builder.defineMacro("__NO_MATH_ERRNO__"); + if (LangOpts.FastMath || LangOpts.FiniteMathOnly) Builder.defineMacro("__FINITE_MATH_ONLY__", "1"); else diff --git a/clang/lib/Frontend/MultiplexConsumer.cpp b/clang/lib/Frontend/MultiplexConsumer.cpp index 5abbb3a235b4..34bbc365e647 100644 --- a/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/clang/lib/Frontend/MultiplexConsumer.cpp @@ -236,10 +236,10 @@ void MultiplexASTMutationListener::AddedAttributeToRecord( MultiplexConsumer::MultiplexConsumer( std::vector<std::unique_ptr<ASTConsumer>> C) - : Consumers(std::move(C)), MutationListener(), DeserializationListener() { + : Consumers(std::move(C)) { // Collect the mutation listeners and deserialization listeners of all // children, and create a multiplex listener each if so. - std::vector<ASTMutationListener*> mutationListeners; + std::vector<ASTMutationListener *> mutationListeners; std::vector<ASTDeserializationListener*> serializationListeners; for (auto &Consumer : Consumers) { if (auto *mutationListener = Consumer->GetASTMutationListener()) diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp index 45df86ef91cd..1d0022bda474 100644 --- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -792,7 +792,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, bool IsStartOfLine = false; char Buffer[256]; - while (1) { + while (true) { // Two lines joined with line continuation ('\' as last character on the // line) must be emitted as one line even though Tok.getLine() returns two // different values. In this situation Tok.isAtStartOfLine() is false even diff --git a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp index 3f2a78127477..3e8d582f90c2 100644 --- a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -14,7 +14,6 @@ #include "clang/Rewrite/Frontend/Rewriters.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/PreprocessorOutputOptions.h" -#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Pragma.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallString.h" @@ -31,10 +30,8 @@ class InclusionRewriter : public PPCallbacks { struct IncludedFile { FileID Id; SrcMgr::CharacteristicKind FileType; - const DirectoryLookup *DirLookup; - IncludedFile(FileID Id, SrcMgr::CharacteristicKind FileType, - const DirectoryLookup *DirLookup) - : Id(Id), FileType(FileType), DirLookup(DirLookup) {} + IncludedFile(FileID Id, SrcMgr::CharacteristicKind FileType) + : Id(Id), FileType(FileType) {} }; Preprocessor &PP; ///< Used to find inclusion directives. SourceManager &SM; ///< Used to read and manage source files. @@ -57,8 +54,7 @@ class InclusionRewriter : public PPCallbacks { public: InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers, bool UseLineDirectives); - void Process(FileID FileId, SrcMgr::CharacteristicKind FileType, - const DirectoryLookup *DirLookup); + void Process(FileID FileId, SrcMgr::CharacteristicKind FileType); void setPredefinesBuffer(const llvm::MemoryBufferRef &Buf) { PredefinesBuffer = Buf; } @@ -162,8 +158,7 @@ void InclusionRewriter::FileChanged(SourceLocation Loc, return; FileID Id = FullSourceLoc(Loc, SM).getFileID(); auto P = FileIncludes.insert( - std::make_pair(LastInclusionLocation, - IncludedFile(Id, NewFileType, PP.GetCurDirLookup()))); + std::make_pair(LastInclusionLocation, IncludedFile(Id, NewFileType))); (void)P; assert(P.second && "Unexpected revisitation of the same include directive"); LastInclusionLocation = SourceLocation(); @@ -256,28 +251,12 @@ bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc) const { return false; } -/// Detect the likely line ending style of \p FromFile by examining the first -/// newline found within it. -static StringRef DetectEOL(const MemoryBufferRef &FromFile) { - // Detect what line endings the file uses, so that added content does not mix - // the style. We need to check for "\r\n" first because "\n\r" will match - // "\r\n\r\n". - const char *Pos = strchr(FromFile.getBufferStart(), '\n'); - if (!Pos) - return "\n"; - if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r') - return "\r\n"; - if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r') - return "\n\r"; - return "\n"; -} - void InclusionRewriter::detectMainFileEOL() { Optional<MemoryBufferRef> FromFile = *SM.getBufferOrNone(SM.getMainFileID()); assert(FromFile); if (!FromFile) return; // Should never happen, but whatever. - MainEOL = DetectEOL(*FromFile); + MainEOL = FromFile->getBuffer().detectEOL(); } /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at @@ -371,8 +350,7 @@ StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it /// and including content of included files recursively. void InclusionRewriter::Process(FileID FileId, - SrcMgr::CharacteristicKind FileType, - const DirectoryLookup *DirLookup) { + SrcMgr::CharacteristicKind FileType) { MemoryBufferRef FromFile; { auto B = SM.getBufferOrNone(FileId); @@ -384,7 +362,7 @@ void InclusionRewriter::Process(FileID FileId, Lexer RawLex(FileId, FromFile, PP.getSourceManager(), PP.getLangOpts()); RawLex.SetCommentRetentionState(false); - StringRef LocalEOL = DetectEOL(FromFile); + StringRef LocalEOL = FromFile.getBuffer().detectEOL(); // Per the GNU docs: "1" indicates entering a new file. if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID()) @@ -433,7 +411,7 @@ void InclusionRewriter::Process(FileID FileId, << Mod->getFullModuleName(true) << "\n"; // Include and recursively process the file. - Process(Inc->Id, Inc->FileType, Inc->DirLookup); + Process(Inc->Id, Inc->FileType); if (Mod) OS << "#pragma clang module end /*" @@ -559,7 +537,7 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, Rewrite->handleModuleBegin(Tok); } while (Tok.isNot(tok::eof)); Rewrite->setPredefinesBuffer(SM.getBufferOrFake(PP.getPredefinesFileID())); - Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User, nullptr); - Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User, nullptr); + Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User); + Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); OS->flush(); } diff --git a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp index 462aeda6e027..fc8fce4b42b8 100644 --- a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -95,8 +95,7 @@ class SDiagsMerger : SerializedDiagnosticReader { AbbrevLookup DiagFlagLookup; public: - SDiagsMerger(SDiagsWriter &Writer) - : SerializedDiagnosticReader(), Writer(Writer) {} + SDiagsMerger(SDiagsWriter &Writer) : Writer(Writer) {} std::error_code mergeRecordsFromFile(const char *File) { return readDiagnostics(File); diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp index 8df7496c6ddd..1c4a76e68953 100644 --- a/clang/lib/Frontend/TextDiagnostic.cpp +++ b/clang/lib/Frontend/TextDiagnostic.cpp @@ -44,7 +44,7 @@ static const enum raw_ostream::Colors savedColor = /// Add highlights to differences in template strings. static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str, bool &Normal, bool Bold) { - while (1) { + while (true) { size_t Pos = Str.find(ToggleHighlight); OS << Str.slice(0, Pos); if (Pos == StringRef::npos) diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index 2759625ae254..f67dceea9135 100644 --- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -541,9 +541,8 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, ExpectedLoc = SourceLocation(); } else { // Lookup file via Preprocessor, like a #include. - const DirectoryLookup *CurDir; Optional<FileEntryRef> File = - PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir, + PP->LookupFile(Pos, Filename, false, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (!File) { Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin), diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 8e18f33af0cb..8a8a13743762 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -57,6 +57,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) { case EmitLLVMOnly: return std::make_unique<EmitLLVMOnlyAction>(); case EmitCodeGenOnly: return std::make_unique<EmitCodeGenOnlyAction>(); case EmitObj: return std::make_unique<EmitObjAction>(); + case ExtractAPI: + return std::make_unique<ExtractAPIAction>(); case FixIt: return std::make_unique<FixItAction>(); case GenerateModule: return std::make_unique<GenerateModuleFromModuleMapAction>(); diff --git a/clang/lib/Headers/__clang_cuda_math.h b/clang/lib/Headers/__clang_cuda_math.h index 538556f394da..e447590393ec 100644 --- a/clang/lib/Headers/__clang_cuda_math.h +++ b/clang/lib/Headers/__clang_cuda_math.h @@ -345,4 +345,4 @@ __DEVICE__ float ynf(int __a, float __b) { return __nv_ynf(__a, __b); } #pragma pop_macro("__DEVICE_VOID__") #pragma pop_macro("__FAST_OR_SLOW") -#endif // __CLANG_CUDA_DEVICE_FUNCTIONS_H__ +#endif // __CLANG_CUDA_MATH_H__ diff --git a/clang/lib/Headers/__clang_hip_runtime_wrapper.h b/clang/lib/Headers/__clang_hip_runtime_wrapper.h index 73021d256cba..10cec58ed12f 100644 --- a/clang/lib/Headers/__clang_hip_runtime_wrapper.h +++ b/clang/lib/Headers/__clang_hip_runtime_wrapper.h @@ -50,6 +50,9 @@ extern "C" { #include <cmath> #include <cstdlib> #include <stdlib.h> +#if __has_include("hip/hip_version.h") +#include "hip/hip_version.h" +#endif // __has_include("hip/hip_version.h") #else typedef __SIZE_TYPE__ size_t; // Define macros which are needed to declare HIP device API's without standard @@ -74,25 +77,35 @@ typedef __SIZE_TYPE__ __hip_size_t; extern "C" { #endif //__cplusplus +#if HIP_VERSION_MAJOR * 100 + HIP_VERSION_MINOR >= 405 +extern "C" __device__ unsigned long long __ockl_dm_alloc(unsigned long long __size); +extern "C" __device__ void __ockl_dm_dealloc(unsigned long long __addr); +__attribute__((weak)) inline __device__ void *malloc(__hip_size_t __size) { + return (void *) __ockl_dm_alloc(__size); +} +__attribute__((weak)) inline __device__ void free(void *__ptr) { + __ockl_dm_dealloc((unsigned long long)__ptr); +} +#else // HIP version check #if __HIP_ENABLE_DEVICE_MALLOC__ __device__ void *__hip_malloc(__hip_size_t __size); __device__ void *__hip_free(void *__ptr); __attribute__((weak)) inline __device__ void *malloc(__hip_size_t __size) { return __hip_malloc(__size); } -__attribute__((weak)) inline __device__ void *free(void *__ptr) { - return __hip_free(__ptr); +__attribute__((weak)) inline __device__ void free(void *__ptr) { + __hip_free(__ptr); } #else __attribute__((weak)) inline __device__ void *malloc(__hip_size_t __size) { __builtin_trap(); return (void *)0; } -__attribute__((weak)) inline __device__ void *free(void *__ptr) { +__attribute__((weak)) inline __device__ void free(void *__ptr) { __builtin_trap(); - return (void *)0; } #endif +#endif // HIP version check #ifdef __cplusplus } // extern "C" diff --git a/clang/lib/Headers/avx2intrin.h b/clang/lib/Headers/avx2intrin.h index 5064c87c2bb1..e33514a60ff3 100644 --- a/clang/lib/Headers/avx2intrin.h +++ b/clang/lib/Headers/avx2intrin.h @@ -26,19 +26,19 @@ static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_abs_epi8(__m256i __a) { - return (__m256i)__builtin_ia32_pabsb256((__v32qi)__a); + return (__m256i)__builtin_elementwise_abs((__v32qs)__a); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_abs_epi16(__m256i __a) { - return (__m256i)__builtin_ia32_pabsw256((__v16hi)__a); + return (__m256i)__builtin_elementwise_abs((__v16hi)__a); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_abs_epi32(__m256i __a) { - return (__m256i)__builtin_ia32_pabsd256((__v8si)__a); + return (__m256i)__builtin_elementwise_abs((__v8si)__a); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 @@ -253,73 +253,73 @@ _mm256_madd_epi16(__m256i __a, __m256i __b) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_max_epi8(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pmaxsb256((__v32qi)__a, (__v32qi)__b); + return (__m256i)__builtin_elementwise_max((__v32qs)__a, (__v32qs)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_max_epi16(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pmaxsw256((__v16hi)__a, (__v16hi)__b); + return (__m256i)__builtin_elementwise_max((__v16hi)__a, (__v16hi)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_max_epi32(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pmaxsd256((__v8si)__a, (__v8si)__b); + return (__m256i)__builtin_elementwise_max((__v8si)__a, (__v8si)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_max_epu8(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pmaxub256((__v32qi)__a, (__v32qi)__b); + return (__m256i)__builtin_elementwise_max((__v32qu)__a, (__v32qu)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_max_epu16(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pmaxuw256((__v16hi)__a, (__v16hi)__b); + return (__m256i)__builtin_elementwise_max((__v16hu)__a, (__v16hu)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_max_epu32(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pmaxud256((__v8si)__a, (__v8si)__b); + return (__m256i)__builtin_elementwise_max((__v8su)__a, (__v8su)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_min_epi8(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pminsb256((__v32qi)__a, (__v32qi)__b); + return (__m256i)__builtin_elementwise_min((__v32qs)__a, (__v32qs)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_min_epi16(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pminsw256((__v16hi)__a, (__v16hi)__b); + return (__m256i)__builtin_elementwise_min((__v16hi)__a, (__v16hi)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_min_epi32(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pminsd256((__v8si)__a, (__v8si)__b); + return (__m256i)__builtin_elementwise_min((__v8si)__a, (__v8si)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_min_epu8(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pminub256((__v32qi)__a, (__v32qi)__b); + return (__m256i)__builtin_elementwise_min((__v32qu)__a, (__v32qu)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_min_epu16(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pminuw256 ((__v16hi)__a, (__v16hi)__b); + return (__m256i)__builtin_elementwise_min((__v16hu)__a, (__v16hu)__b); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_min_epu32(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pminud256((__v8si)__a, (__v8si)__b); + return (__m256i)__builtin_elementwise_min((__v8su)__a, (__v8su)__b); } static __inline__ int __DEFAULT_FN_ATTRS256 diff --git a/clang/lib/Headers/avx512bwintrin.h b/clang/lib/Headers/avx512bwintrin.h index 6aee8aed8487..522ef100bab1 100644 --- a/clang/lib/Headers/avx512bwintrin.h +++ b/clang/lib/Headers/avx512bwintrin.h @@ -485,7 +485,7 @@ _mm512_mask_blend_epi16 (__mmask32 __U, __m512i __A, __m512i __W) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_abs_epi8 (__m512i __A) { - return (__m512i)__builtin_ia32_pabsb512((__v64qi)__A); + return (__m512i)__builtin_elementwise_abs((__v64qs)__A); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -507,7 +507,7 @@ _mm512_maskz_abs_epi8 (__mmask64 __U, __m512i __A) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_abs_epi16 (__m512i __A) { - return (__m512i)__builtin_ia32_pabsw512((__v32hi)__A); + return (__m512i)__builtin_elementwise_abs((__v32hi)__A); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -751,7 +751,7 @@ _mm512_maskz_avg_epu16 (__mmask32 __U, __m512i __A, __m512i __B) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_max_epi8 (__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pmaxsb512((__v64qi) __A, (__v64qi) __B); + return (__m512i)__builtin_elementwise_max((__v64qs) __A, (__v64qs) __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -773,7 +773,7 @@ _mm512_mask_max_epi8 (__m512i __W, __mmask64 __M, __m512i __A, __m512i __B) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_max_epi16 (__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pmaxsw512((__v32hi) __A, (__v32hi) __B); + return (__m512i)__builtin_elementwise_max((__v32hi) __A, (__v32hi) __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -796,7 +796,7 @@ _mm512_mask_max_epi16 (__m512i __W, __mmask32 __M, __m512i __A, static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_max_epu8 (__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pmaxub512((__v64qi)__A, (__v64qi)__B); + return (__m512i)__builtin_elementwise_max((__v64qu)__A, (__v64qu)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -818,7 +818,7 @@ _mm512_mask_max_epu8 (__m512i __W, __mmask64 __M, __m512i __A, __m512i __B) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_max_epu16 (__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pmaxuw512((__v32hi)__A, (__v32hi)__B); + return (__m512i)__builtin_elementwise_max((__v32hu)__A, (__v32hu)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -840,7 +840,7 @@ _mm512_mask_max_epu16 (__m512i __W, __mmask32 __M, __m512i __A, __m512i __B) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_min_epi8 (__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pminsb512((__v64qi) __A, (__v64qi) __B); + return (__m512i)__builtin_elementwise_min((__v64qs) __A, (__v64qs) __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -862,7 +862,7 @@ _mm512_mask_min_epi8 (__m512i __W, __mmask64 __M, __m512i __A, __m512i __B) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_min_epi16 (__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pminsw512((__v32hi) __A, (__v32hi) __B); + return (__m512i)__builtin_elementwise_min((__v32hi) __A, (__v32hi) __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -884,7 +884,7 @@ _mm512_mask_min_epi16 (__m512i __W, __mmask32 __M, __m512i __A, __m512i __B) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_min_epu8 (__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pminub512((__v64qi)__A, (__v64qi)__B); + return (__m512i)__builtin_elementwise_min((__v64qu)__A, (__v64qu)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -906,7 +906,7 @@ _mm512_mask_min_epu8 (__m512i __W, __mmask64 __M, __m512i __A, __m512i __B) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_min_epu16 (__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pminuw512((__v32hi)__A, (__v32hi)__B); + return (__m512i)__builtin_elementwise_min((__v32hu)__A, (__v32hu)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 diff --git a/clang/lib/Headers/avx512fintrin.h b/clang/lib/Headers/avx512fintrin.h index df298640523b..50e0e287d9fc 100644 --- a/clang/lib/Headers/avx512fintrin.h +++ b/clang/lib/Headers/avx512fintrin.h @@ -26,6 +26,10 @@ typedef unsigned short __v32hu __attribute__((__vector_size__(64))); typedef unsigned long long __v8du __attribute__((__vector_size__(64))); typedef unsigned int __v16su __attribute__((__vector_size__(64))); +/* We need an explicitly signed variant for char. Note that this shouldn't + * appear in the interface though. */ +typedef signed char __v64qs __attribute__((__vector_size__(64))); + typedef float __m512 __attribute__((__vector_size__(64), __aligned__(64))); typedef double __m512d __attribute__((__vector_size__(64), __aligned__(64))); typedef long long __m512i __attribute__((__vector_size__(64), __aligned__(64))); @@ -1086,7 +1090,7 @@ static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_max_epi32(__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pmaxsd512((__v16si)__A, (__v16si)__B); + return (__m512i)__builtin_elementwise_max((__v16si)__A, (__v16si)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -1108,7 +1112,7 @@ _mm512_maskz_max_epi32 (__mmask16 __M, __m512i __A, __m512i __B) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_max_epu32(__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pmaxud512((__v16si)__A, (__v16si)__B); + return (__m512i)__builtin_elementwise_max((__v16su)__A, (__v16su)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -1130,7 +1134,7 @@ _mm512_maskz_max_epu32 (__mmask16 __M, __m512i __A, __m512i __B) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_max_epi64(__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pmaxsq512((__v8di)__A, (__v8di)__B); + return (__m512i)__builtin_elementwise_max((__v8di)__A, (__v8di)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -1152,7 +1156,7 @@ _mm512_maskz_max_epi64 (__mmask8 __M, __m512i __A, __m512i __B) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_max_epu64(__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pmaxuq512((__v8di)__A, (__v8di)__B); + return (__m512i)__builtin_elementwise_max((__v8du)__A, (__v8du)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -1321,7 +1325,7 @@ static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_min_epi32(__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pminsd512((__v16si)__A, (__v16si)__B); + return (__m512i)__builtin_elementwise_min((__v16si)__A, (__v16si)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -1343,7 +1347,7 @@ _mm512_maskz_min_epi32 (__mmask16 __M, __m512i __A, __m512i __B) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_min_epu32(__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pminud512((__v16si)__A, (__v16si)__B); + return (__m512i)__builtin_elementwise_min((__v16su)__A, (__v16su)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -1365,7 +1369,7 @@ _mm512_maskz_min_epu32 (__mmask16 __M, __m512i __A, __m512i __B) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_min_epi64(__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pminsq512((__v8di)__A, (__v8di)__B); + return (__m512i)__builtin_elementwise_min((__v8di)__A, (__v8di)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -1387,7 +1391,7 @@ _mm512_maskz_min_epi64 (__mmask8 __M, __m512i __A, __m512i __B) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_min_epu64(__m512i __A, __m512i __B) { - return (__m512i)__builtin_ia32_pminuq512((__v8di)__A, (__v8di)__B); + return (__m512i)__builtin_elementwise_min((__v8du)__A, (__v8du)__B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -1846,7 +1850,7 @@ _mm512_mask_ceil_pd (__m512d __W, __mmask8 __U, __m512d __A) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_abs_epi64(__m512i __A) { - return (__m512i)__builtin_ia32_pabsq512((__v8di)__A); + return (__m512i)__builtin_elementwise_abs((__v8di)__A); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -1868,7 +1872,7 @@ _mm512_maskz_abs_epi64 (__mmask8 __U, __m512i __A) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_abs_epi32(__m512i __A) { - return (__m512i)__builtin_ia32_pabsd512((__v16si) __A); + return (__m512i)__builtin_elementwise_abs((__v16si) __A); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -9320,11 +9324,11 @@ static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_mul_epi64(__m512 } static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_and_epi64(__m512i __W) { - return __builtin_ia32_reduce_and_q512(__W); + return __builtin_reduce_and((__v8di)__W); } static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_or_epi64(__m512i __W) { - return __builtin_ia32_reduce_or_q512(__W); + return __builtin_reduce_or((__v8di)__W); } static __inline__ long long __DEFAULT_FN_ATTRS512 @@ -9342,13 +9346,13 @@ _mm512_mask_reduce_mul_epi64(__mmask8 __M, __m512i __W) { static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_and_epi64(__mmask8 __M, __m512i __W) { __W = _mm512_mask_mov_epi64(_mm512_set1_epi64(~0ULL), __M, __W); - return __builtin_ia32_reduce_and_q512(__W); + return __builtin_reduce_and((__v8di)__W); } static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_or_epi64(__mmask8 __M, __m512i __W) { __W = _mm512_maskz_mov_epi64(__M, __W); - return __builtin_ia32_reduce_or_q512(__W); + return __builtin_reduce_or((__v8di)__W); } // -0.0 is used to ignore the start value since it is the neutral value of @@ -9386,12 +9390,12 @@ _mm512_reduce_mul_epi32(__m512i __W) { static __inline__ int __DEFAULT_FN_ATTRS512 _mm512_reduce_and_epi32(__m512i __W) { - return __builtin_ia32_reduce_and_d512((__v16si)__W); + return __builtin_reduce_and((__v16si)__W); } static __inline__ int __DEFAULT_FN_ATTRS512 _mm512_reduce_or_epi32(__m512i __W) { - return __builtin_ia32_reduce_or_d512((__v16si)__W); + return __builtin_reduce_or((__v16si)__W); } static __inline__ int __DEFAULT_FN_ATTRS512 @@ -9409,13 +9413,13 @@ _mm512_mask_reduce_mul_epi32( __mmask16 __M, __m512i __W) { static __inline__ int __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_and_epi32( __mmask16 __M, __m512i __W) { __W = _mm512_mask_mov_epi32(_mm512_set1_epi32(~0U), __M, __W); - return __builtin_ia32_reduce_and_d512((__v16si)__W); + return __builtin_reduce_and((__v16si)__W); } static __inline__ int __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_or_epi32(__mmask16 __M, __m512i __W) { __W = _mm512_maskz_mov_epi32(__M, __W); - return __builtin_ia32_reduce_or_d512((__v16si)__W); + return __builtin_reduce_or((__v16si)__W); } static __inline__ float __DEFAULT_FN_ATTRS512 @@ -9442,89 +9446,89 @@ _mm512_mask_reduce_mul_ps(__mmask16 __M, __m512 __W) { static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_max_epi64(__m512i __V) { - return __builtin_ia32_reduce_smax_q512(__V); + return __builtin_reduce_max((__v8di)__V); } static __inline__ unsigned long long __DEFAULT_FN_ATTRS512 _mm512_reduce_max_epu64(__m512i __V) { - return __builtin_ia32_reduce_umax_q512(__V); + return __builtin_reduce_max((__v8du)__V); } static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_reduce_min_epi64(__m512i __V) { - return __builtin_ia32_reduce_smin_q512(__V); + return __builtin_reduce_min((__v8di)__V); } static __inline__ unsigned long long __DEFAULT_FN_ATTRS512 _mm512_reduce_min_epu64(__m512i __V) { - return __builtin_ia32_reduce_umin_q512(__V); + return __builtin_reduce_min((__v8du)__V); } static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_max_epi64(__mmask8 __M, __m512i __V) { __V = _mm512_mask_mov_epi64(_mm512_set1_epi64(-__LONG_LONG_MAX__ - 1LL), __M, __V); - return __builtin_ia32_reduce_smax_q512(__V); + return __builtin_reduce_max((__v8di)__V); } static __inline__ unsigned long long __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_max_epu64(__mmask8 __M, __m512i __V) { __V = _mm512_maskz_mov_epi64(__M, __V); - return __builtin_ia32_reduce_umax_q512(__V); + return __builtin_reduce_max((__v8du)__V); } static __inline__ long long __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_min_epi64(__mmask8 __M, __m512i __V) { __V = _mm512_mask_mov_epi64(_mm512_set1_epi64(__LONG_LONG_MAX__), __M, __V); - return __builtin_ia32_reduce_smin_q512(__V); + return __builtin_reduce_min((__v8di)__V); } static __inline__ unsigned long long __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_min_epu64(__mmask8 __M, __m512i __V) { __V = _mm512_mask_mov_epi64(_mm512_set1_epi64(~0ULL), __M, __V); - return __builtin_ia32_reduce_umin_q512(__V); + return __builtin_reduce_min((__v8du)__V); } static __inline__ int __DEFAULT_FN_ATTRS512 _mm512_reduce_max_epi32(__m512i __V) { - return __builtin_ia32_reduce_smax_d512((__v16si)__V); + return __builtin_reduce_max((__v16si)__V); } static __inline__ unsigned int __DEFAULT_FN_ATTRS512 _mm512_reduce_max_epu32(__m512i __V) { - return __builtin_ia32_reduce_umax_d512((__v16si)__V); + return __builtin_reduce_max((__v16su)__V); } static __inline__ int __DEFAULT_FN_ATTRS512 _mm512_reduce_min_epi32(__m512i __V) { - return __builtin_ia32_reduce_smin_d512((__v16si)__V); + return __builtin_reduce_min((__v16si)__V); } static __inline__ unsigned int __DEFAULT_FN_ATTRS512 _mm512_reduce_min_epu32(__m512i __V) { - return __builtin_ia32_reduce_umin_d512((__v16si)__V); + return __builtin_reduce_min((__v16su)__V); } static __inline__ int __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_max_epi32(__mmask16 __M, __m512i __V) { __V = _mm512_mask_mov_epi32(_mm512_set1_epi32(-__INT_MAX__ - 1), __M, __V); - return __builtin_ia32_reduce_smax_d512((__v16si)__V); + return __builtin_reduce_max((__v16si)__V); } static __inline__ unsigned int __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_max_epu32(__mmask16 __M, __m512i __V) { __V = _mm512_maskz_mov_epi32(__M, __V); - return __builtin_ia32_reduce_umax_d512((__v16si)__V); + return __builtin_reduce_max((__v16su)__V); } static __inline__ int __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_min_epi32(__mmask16 __M, __m512i __V) { __V = _mm512_mask_mov_epi32(_mm512_set1_epi32(__INT_MAX__), __M, __V); - return __builtin_ia32_reduce_smin_d512((__v16si)__V); + return __builtin_reduce_min((__v16si)__V); } static __inline__ unsigned int __DEFAULT_FN_ATTRS512 _mm512_mask_reduce_min_epu32(__mmask16 __M, __m512i __V) { __V = _mm512_mask_mov_epi32(_mm512_set1_epi32(~0U), __M, __V); - return __builtin_ia32_reduce_umin_d512((__v16si)__V); + return __builtin_reduce_min((__v16su)__V); } static __inline__ double __DEFAULT_FN_ATTRS512 diff --git a/clang/lib/Headers/avx512vlintrin.h b/clang/lib/Headers/avx512vlintrin.h index 0519dba59081..178c9dbc0e6e 100644 --- a/clang/lib/Headers/avx512vlintrin.h +++ b/clang/lib/Headers/avx512vlintrin.h @@ -2988,7 +2988,7 @@ _mm256_maskz_abs_epi32(__mmask8 __U, __m256i __A) { static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_abs_epi64 (__m128i __A) { - return (__m128i)__builtin_ia32_pabsq128((__v2di)__A); + return (__m128i)__builtin_elementwise_abs((__v2di)__A); } static __inline__ __m128i __DEFAULT_FN_ATTRS128 @@ -3007,7 +3007,7 @@ _mm_maskz_abs_epi64 (__mmask8 __U, __m128i __A) { static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_abs_epi64 (__m256i __A) { - return (__m256i)__builtin_ia32_pabsq256 ((__v4di)__A); + return (__m256i)__builtin_elementwise_abs((__v4di)__A); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 @@ -3054,7 +3054,7 @@ _mm256_mask_max_epi32(__m256i __W, __mmask8 __M, __m256i __A, __m256i __B) { static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_max_epi64 (__m128i __A, __m128i __B) { - return (__m128i)__builtin_ia32_pmaxsq128((__v2di)__A, (__v2di)__B); + return (__m128i)__builtin_elementwise_max((__v2di)__A, (__v2di)__B); } static __inline__ __m128i __DEFAULT_FN_ATTRS128 @@ -3073,7 +3073,7 @@ _mm_mask_max_epi64 (__m128i __W, __mmask8 __M, __m128i __A, __m128i __B) { static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_max_epi64 (__m256i __A, __m256i __B) { - return (__m256i)__builtin_ia32_pmaxsq256((__v4di)__A, (__v4di)__B); + return (__m256i)__builtin_elementwise_max((__v4di)__A, (__v4di)__B); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 @@ -3120,7 +3120,7 @@ _mm256_mask_max_epu32(__m256i __W, __mmask8 __M, __m256i __A, __m256i __B) { static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_max_epu64 (__m128i __A, __m128i __B) { - return (__m128i)__builtin_ia32_pmaxuq128((__v2di)__A, (__v2di)__B); + return (__m128i)__builtin_elementwise_max((__v2du)__A, (__v2du)__B); } static __inline__ __m128i __DEFAULT_FN_ATTRS128 @@ -3139,7 +3139,7 @@ _mm_mask_max_epu64 (__m128i __W, __mmask8 __M, __m128i __A, __m128i __B) { static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_max_epu64 (__m256i __A, __m256i __B) { - return (__m256i)__builtin_ia32_pmaxuq256((__v4di)__A, (__v4di)__B); + return (__m256i)__builtin_elementwise_max((__v4du)__A, (__v4du)__B); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 @@ -3186,7 +3186,7 @@ _mm256_mask_min_epi32(__m256i __W, __mmask8 __M, __m256i __A, __m256i __B) { static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_min_epi64 (__m128i __A, __m128i __B) { - return (__m128i)__builtin_ia32_pminsq128((__v2di)__A, (__v2di)__B); + return (__m128i)__builtin_elementwise_min((__v2di)__A, (__v2di)__B); } static __inline__ __m128i __DEFAULT_FN_ATTRS128 @@ -3205,7 +3205,7 @@ _mm_maskz_min_epi64 (__mmask8 __M, __m128i __A, __m128i __B) { static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_min_epi64 (__m256i __A, __m256i __B) { - return (__m256i)__builtin_ia32_pminsq256((__v4di)__A, (__v4di)__B); + return (__m256i)__builtin_elementwise_min((__v4di)__A, (__v4di)__B); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 @@ -3252,7 +3252,7 @@ _mm256_mask_min_epu32(__m256i __W, __mmask8 __M, __m256i __A, __m256i __B) { static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_min_epu64 (__m128i __A, __m128i __B) { - return (__m128i)__builtin_ia32_pminuq128((__v2di)__A, (__v2di)__B); + return (__m128i)__builtin_elementwise_min((__v2du)__A, (__v2du)__B); } static __inline__ __m128i __DEFAULT_FN_ATTRS128 @@ -3271,7 +3271,7 @@ _mm_maskz_min_epu64 (__mmask8 __M, __m128i __A, __m128i __B) { static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_min_epu64 (__m256i __A, __m256i __B) { - return (__m256i)__builtin_ia32_pminuq256((__v4di)__A, (__v4di)__B); + return (__m256i)__builtin_elementwise_min((__v4du)__A, (__v4du)__B); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 diff --git a/clang/lib/Headers/cetintrin.h b/clang/lib/Headers/cetintrin.h index 4290e9d7355b..019cab0261e7 100644 --- a/clang/lib/Headers/cetintrin.h +++ b/clang/lib/Headers/cetintrin.h @@ -42,10 +42,20 @@ static __inline__ unsigned int __DEFAULT_FN_ATTRS _rdsspd(unsigned int __a) { return __builtin_ia32_rdsspd(__a); } +static __inline__ unsigned int __DEFAULT_FN_ATTRS _rdsspd_i32() { + unsigned int t; + return __builtin_ia32_rdsspd(t); +} + #ifdef __x86_64__ static __inline__ unsigned long long __DEFAULT_FN_ATTRS _rdsspq(unsigned long long __a) { return __builtin_ia32_rdsspq(__a); } + +static __inline__ unsigned long long __DEFAULT_FN_ATTRS _rdsspq_i64() { + unsigned long long t; + return __builtin_ia32_rdsspq(t); +} #endif /* __x86_64__ */ #ifdef __x86_64__ diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h index 6df1b4a11172..5d262a60735f 100644 --- a/clang/lib/Headers/cpuid.h +++ b/clang/lib/Headers/cpuid.h @@ -200,7 +200,7 @@ #define bit_AMXINT8 0x02000000 /* Features in %eax for leaf 7 sub-leaf 1 */ -#define bit_AVXVNNI 0x00000008 +#define bit_AVXVNNI 0x00000010 #define bit_AVX512BF16 0x00000020 #define bit_HRESET 0x00400000 diff --git a/clang/lib/Headers/emmintrin.h b/clang/lib/Headers/emmintrin.h index 6e9c3032c21f..4618b808efc4 100644 --- a/clang/lib/Headers/emmintrin.h +++ b/clang/lib/Headers/emmintrin.h @@ -2375,7 +2375,7 @@ _mm_madd_epi16(__m128i __a, __m128i __b) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_max_epi16(__m128i __a, __m128i __b) { - return (__m128i)__builtin_ia32_pmaxsw128((__v8hi)__a, (__v8hi)__b); + return (__m128i)__builtin_elementwise_max((__v8hi)__a, (__v8hi)__b); } /// Compares corresponding elements of two 128-bit unsigned [16 x i8] @@ -2395,7 +2395,7 @@ _mm_max_epi16(__m128i __a, __m128i __b) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_max_epu8(__m128i __a, __m128i __b) { - return (__m128i)__builtin_ia32_pmaxub128((__v16qi)__a, (__v16qi)__b); + return (__m128i)__builtin_elementwise_max((__v16qu)__a, (__v16qu)__b); } /// Compares corresponding elements of two 128-bit signed [8 x i16] @@ -2415,7 +2415,7 @@ _mm_max_epu8(__m128i __a, __m128i __b) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_min_epi16(__m128i __a, __m128i __b) { - return (__m128i)__builtin_ia32_pminsw128((__v8hi)__a, (__v8hi)__b); + return (__m128i)__builtin_elementwise_min((__v8hi)__a, (__v8hi)__b); } /// Compares corresponding elements of two 128-bit unsigned [16 x i8] @@ -2435,7 +2435,7 @@ _mm_min_epi16(__m128i __a, __m128i __b) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_min_epu8(__m128i __a, __m128i __b) { - return (__m128i)__builtin_ia32_pminub128((__v16qi)__a, (__v16qi)__b); + return (__m128i)__builtin_elementwise_min((__v16qu)__a, (__v16qu)__b); } /// Multiplies the corresponding elements of two signed [8 x i16] diff --git a/clang/lib/Headers/limits.h b/clang/lib/Headers/limits.h index c653580bac4e..c2d3a7cf4353 100644 --- a/clang/lib/Headers/limits.h +++ b/clang/lib/Headers/limits.h @@ -62,6 +62,24 @@ #define CHAR_BIT __CHAR_BIT__ +/* C2x 5.2.4.2.1 */ +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +#define BOOL_WIDTH __BOOL_WIDTH__ +#define CHAR_WIDTH CHAR_BIT +#define SCHAR_WIDTH CHAR_BIT +#define UCHAR_WIDTH CHAR_BIT +#define USHRT_WIDTH __SHRT_WIDTH__ +#define SHRT_WIDTH __SHRT_WIDTH__ +#define UINT_WIDTH __INT_WIDTH__ +#define INT_WIDTH __INT_WIDTH__ +#define ULONG_WIDTH __LONG_WIDTH__ +#define LONG_WIDTH __LONG_WIDTH__ +#define ULLONG_WIDTH __LLONG_WIDTH__ +#define LLONG_WIDTH __LLONG_WIDTH__ +#endif + #ifdef __CHAR_UNSIGNED__ /* -funsigned-char */ #define CHAR_MIN 0 #define CHAR_MAX UCHAR_MAX diff --git a/clang/lib/Headers/opencl-c-base.h b/clang/lib/Headers/opencl-c-base.h index 9c81ddb5e2a7..06b78da63e69 100644 --- a/clang/lib/Headers/opencl-c-base.h +++ b/clang/lib/Headers/opencl-c-base.h @@ -68,6 +68,7 @@ // For the SPIR and SPIR-V target all features are supported. #if defined(__SPIR__) || defined(__SPIRV__) #define __opencl_c_atomic_scope_all_devices 1 +#define __opencl_c_read_write_images 1 #endif // defined(__SPIR__) #endif // (__OPENCL_CPP_VERSION__ == 202100 || __OPENCL_C_VERSION__ == 300) @@ -498,12 +499,14 @@ typedef int clk_profiling_info; #define MAX_WORK_DIM 3 +#ifdef __opencl_c_device_enqueue typedef struct { unsigned int workDimension; size_t globalWorkOffset[MAX_WORK_DIM]; size_t globalWorkSize[MAX_WORK_DIM]; size_t localWorkSize[MAX_WORK_DIM]; } ndrange_t; +#endif // __opencl_c_device_enqueue #endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) @@ -600,9 +603,11 @@ typedef struct { // C++ for OpenCL - __remove_address_space #if defined(__OPENCL_CPP_VERSION__) template <typename _Tp> struct __remove_address_space { using type = _Tp; }; +#if defined(__opencl_c_generic_address_space) template <typename _Tp> struct __remove_address_space<__generic _Tp> { using type = _Tp; }; +#endif template <typename _Tp> struct __remove_address_space<__global _Tp> { using type = _Tp; }; diff --git a/clang/lib/Headers/opencl-c.h b/clang/lib/Headers/opencl-c.h index 77a7a8b9bb3a..8fde2fa29899 100644 --- a/clang/lib/Headers/opencl-c.h +++ b/clang/lib/Headers/opencl-c.h @@ -11,11 +11,11 @@ #include "opencl-c-base.h" -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_images) #ifndef cl_khr_depth_images #define cl_khr_depth_images #endif //cl_khr_depth_images -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_images) #if __OPENCL_C_VERSION__ < CL_VERSION_2_0 #ifdef cl_khr_3d_image_writes @@ -15585,7 +15585,7 @@ half4 __purefn __ovld read_imageh(read_only image1d_buffer_t image, int coord); #endif //cl_khr_fp16 // Image read functions for read_write images -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) float4 __purefn __ovld read_imagef(read_write image1d_t image, int coord); int4 __purefn __ovld read_imagei(read_write image1d_t image, int coord); uint4 __purefn __ovld read_imageui(read_write image1d_t image, int coord); @@ -15628,7 +15628,6 @@ float __purefn __ovld read_imagef(read_write image2d_msaa_depth_t image, int2 co float __purefn __ovld read_imagef(read_write image2d_array_msaa_depth_t image, int4 coord, int sample); #endif //cl_khr_gl_msaa_sharing -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #ifdef cl_khr_mipmap_image float4 __purefn __ovld read_imagef(read_write image1d_t image, sampler_t sampler, float coord, float lod); int4 __purefn __ovld read_imagei(read_write image1d_t image, sampler_t sampler, float coord, float lod); @@ -15679,7 +15678,6 @@ int4 __purefn __ovld read_imagei(read_write image3d_t image, sampler_t sampler, uint4 __purefn __ovld read_imageui(read_write image3d_t image, sampler_t sampler, float4 coord, float4 gradientX, float4 gradientY); #endif //cl_khr_mipmap_image -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // Image read functions returning half4 type #ifdef cl_khr_fp16 @@ -15690,7 +15688,7 @@ half4 __purefn __ovld read_imageh(read_write image1d_array_t image, int2 coord); half4 __purefn __ovld read_imageh(read_write image2d_array_t image, int4 coord); half4 __purefn __ovld read_imageh(read_write image1d_buffer_t image, int coord); #endif //cl_khr_fp16 -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) /** * Write color value to location specified by coordinate @@ -15834,7 +15832,7 @@ void __ovld write_imageh(write_only image1d_buffer_t image, int coord, half4 col #endif //cl_khr_fp16 // Image write functions for read_write images -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) void __ovld write_imagef(read_write image2d_t image, int2 coord, float4 color); void __ovld write_imagei(read_write image2d_t image, int2 coord, int4 color); void __ovld write_imageui(read_write image2d_t image, int2 coord, uint4 color); @@ -15866,7 +15864,6 @@ void __ovld write_imagef(read_write image2d_depth_t image, int2 coord, float col void __ovld write_imagef(read_write image2d_array_depth_t image, int4 coord, float color); #endif //cl_khr_depth_images -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #if defined(cl_khr_mipmap_image_writes) void __ovld write_imagef(read_write image1d_t image, int coord, int lod, float4 color); void __ovld write_imagei(read_write image1d_t image, int coord, int lod, int4 color); @@ -15894,7 +15891,6 @@ void __ovld write_imageui(read_write image3d_t image, int4 coord, int lod, uint4 #endif //cl_khr_3d_image_writes #endif //cl_khr_mipmap_image_writes -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // Image write functions for half4 type #ifdef cl_khr_fp16 @@ -15907,7 +15903,7 @@ void __ovld write_imageh(read_write image1d_array_t image, int2 coord, half4 col void __ovld write_imageh(read_write image2d_array_t image, int4 coord, half4 color); void __ovld write_imageh(read_write image1d_buffer_t image, int coord, half4 color); #endif //cl_khr_fp16 -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) // Note: In OpenCL v1.0/1.1/1.2, image argument of image query builtin functions does not have // access qualifier, which by default assume read_only access qualifier. Image query builtin @@ -15955,7 +15951,7 @@ int __ovld __cnfn get_image_width(write_only image2d_array_msaa_t image); int __ovld __cnfn get_image_width(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) int __ovld __cnfn get_image_width(read_write image1d_t image); int __ovld __cnfn get_image_width(read_write image1d_buffer_t image); int __ovld __cnfn get_image_width(read_write image2d_t image); @@ -15972,7 +15968,7 @@ int __ovld __cnfn get_image_width(read_write image2d_msaa_depth_t image); int __ovld __cnfn get_image_width(read_write image2d_array_msaa_t image); int __ovld __cnfn get_image_width(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) /** * Return the image height in pixels. @@ -16007,7 +16003,7 @@ int __ovld __cnfn get_image_height(write_only image2d_array_msaa_t image); int __ovld __cnfn get_image_height(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) int __ovld __cnfn get_image_height(read_write image2d_t image); int __ovld __cnfn get_image_height(read_write image3d_t image); int __ovld __cnfn get_image_height(read_write image2d_array_t image); @@ -16021,7 +16017,7 @@ int __ovld __cnfn get_image_height(read_write image2d_msaa_depth_t image); int __ovld __cnfn get_image_height(read_write image2d_array_msaa_t image); int __ovld __cnfn get_image_height(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) /** * Return the image depth in pixels. @@ -16032,9 +16028,9 @@ int __ovld __cnfn get_image_depth(read_only image3d_t image); int __ovld __cnfn get_image_depth(write_only image3d_t image); #endif -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) int __ovld __cnfn get_image_depth(read_write image3d_t image); -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) // OpenCL Extension v2.0 s9.18 - Mipmaps #if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) @@ -16053,9 +16049,11 @@ int __ovld get_image_num_mip_levels(write_only image2d_t image); int __ovld get_image_num_mip_levels(write_only image3d_t image); #endif +#if defined(__opencl_c_read_write_images) int __ovld get_image_num_mip_levels(read_write image1d_t image); int __ovld get_image_num_mip_levels(read_write image2d_t image); int __ovld get_image_num_mip_levels(read_write image3d_t image); +#endif //defined(__opencl_c_read_write_images) int __ovld get_image_num_mip_levels(read_only image1d_array_t image); int __ovld get_image_num_mip_levels(read_only image2d_array_t image); @@ -16067,10 +16065,12 @@ int __ovld get_image_num_mip_levels(write_only image2d_array_t image); int __ovld get_image_num_mip_levels(write_only image2d_array_depth_t image); int __ovld get_image_num_mip_levels(write_only image2d_depth_t image); +#if defined(__opencl_c_read_write_images) int __ovld get_image_num_mip_levels(read_write image1d_array_t image); int __ovld get_image_num_mip_levels(read_write image2d_array_t image); int __ovld get_image_num_mip_levels(read_write image2d_array_depth_t image); int __ovld get_image_num_mip_levels(read_write image2d_depth_t image); +#endif //defined(__opencl_c_read_write_images) #endif //cl_khr_mipmap_image #endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) @@ -16130,7 +16130,7 @@ int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_msaa_t im int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) int __ovld __cnfn get_image_channel_data_type(read_write image1d_t image); int __ovld __cnfn get_image_channel_data_type(read_write image1d_buffer_t image); int __ovld __cnfn get_image_channel_data_type(read_write image2d_t image); @@ -16147,7 +16147,7 @@ int __ovld __cnfn get_image_channel_data_type(read_write image2d_msaa_depth_t im int __ovld __cnfn get_image_channel_data_type(read_write image2d_array_msaa_t image); int __ovld __cnfn get_image_channel_data_type(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) /** * Return the image channel order. Valid values are: @@ -16202,7 +16202,7 @@ int __ovld __cnfn get_image_channel_order(write_only image2d_array_msaa_t image) int __ovld __cnfn get_image_channel_order(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) int __ovld __cnfn get_image_channel_order(read_write image1d_t image); int __ovld __cnfn get_image_channel_order(read_write image1d_buffer_t image); int __ovld __cnfn get_image_channel_order(read_write image2d_t image); @@ -16219,7 +16219,7 @@ int __ovld __cnfn get_image_channel_order(read_write image2d_msaa_depth_t image) int __ovld __cnfn get_image_channel_order(read_write image2d_array_msaa_t image); int __ovld __cnfn get_image_channel_order(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) /** * Return the 2D image width and height as an int2 @@ -16252,7 +16252,7 @@ int2 __ovld __cnfn get_image_dim(write_only image2d_array_msaa_t image); int2 __ovld __cnfn get_image_dim(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) int2 __ovld __cnfn get_image_dim(read_write image2d_t image); int2 __ovld __cnfn get_image_dim(read_write image2d_array_t image); #ifdef cl_khr_depth_images @@ -16265,7 +16265,7 @@ int2 __ovld __cnfn get_image_dim(read_write image2d_msaa_depth_t image); int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_t image); int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) /** * Return the 3D image width, height, and depth as an @@ -16277,9 +16277,9 @@ int4 __ovld __cnfn get_image_dim(read_only image3d_t image); #ifdef cl_khr_3d_image_writes int4 __ovld __cnfn get_image_dim(write_only image3d_t image); #endif -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) int4 __ovld __cnfn get_image_dim(read_write image3d_t image); -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) /** * Return the image array size. @@ -16305,7 +16305,7 @@ size_t __ovld __cnfn get_image_array_size(write_only image2d_array_msaa_t image_ size_t __ovld __cnfn get_image_array_size(write_only image2d_array_msaa_depth_t image_array); #endif //cl_khr_gl_msaa_sharing -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) size_t __ovld __cnfn get_image_array_size(read_write image1d_array_t image_array); size_t __ovld __cnfn get_image_array_size(read_write image2d_array_t image_array); #ifdef cl_khr_depth_images @@ -16315,7 +16315,7 @@ size_t __ovld __cnfn get_image_array_size(read_write image2d_array_depth_t image size_t __ovld __cnfn get_image_array_size(read_write image2d_array_msaa_t image_array); size_t __ovld __cnfn get_image_array_size(read_write image2d_array_msaa_depth_t image_array); #endif //cl_khr_gl_msaa_sharing -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) /** * Return the number of samples associated with image @@ -16331,12 +16331,12 @@ int __ovld get_image_num_samples(write_only image2d_msaa_depth_t image); int __ovld get_image_num_samples(write_only image2d_array_msaa_t image); int __ovld get_image_num_samples(write_only image2d_array_msaa_depth_t image); -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) int __ovld get_image_num_samples(read_write image2d_msaa_t image); int __ovld get_image_num_samples(read_write image2d_msaa_depth_t image); int __ovld get_image_num_samples(read_write image2d_array_msaa_t image); int __ovld get_image_num_samples(read_write image2d_array_msaa_depth_t image); -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_read_write_images) #endif // OpenCL v2.0 s6.13.15 - Work-group Functions @@ -16450,6 +16450,7 @@ bool __ovld is_valid_reserve_id(reserve_id_t reserve_id); // OpenCL v2.0 s6.13.17 - Enqueue Kernels #if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#ifdef __opencl_c_device_enqueue ndrange_t __ovld ndrange_1D(size_t); ndrange_t __ovld ndrange_1D(size_t, size_t); ndrange_t __ovld ndrange_1D(size_t, size_t, size_t); @@ -16477,6 +16478,7 @@ bool __ovld is_valid_event (clk_event_t event); void __ovld capture_event_profiling_info(clk_event_t, clk_profiling_info, __global void* value); queue_t __ovld get_default_queue(void); +#endif //__opencl_c_device_enqueue #endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL Extension v2.0 s9.17 - Sub-groups @@ -17572,34 +17574,38 @@ uint16 __ovld __conv intel_sub_group_shuffle_xor( uint16 x, uint c ); long __ovld __conv intel_sub_group_shuffle_xor( long x, uint c ); ulong __ovld __conv intel_sub_group_shuffle_xor( ulong x, uint c ); +#if defined(__opencl_c_images) uint __ovld __conv intel_sub_group_block_read( read_only image2d_t image, int2 coord ); uint2 __ovld __conv intel_sub_group_block_read2( read_only image2d_t image, int2 coord ); uint4 __ovld __conv intel_sub_group_block_read4( read_only image2d_t image, int2 coord ); uint8 __ovld __conv intel_sub_group_block_read8( read_only image2d_t image, int2 coord ); +#endif -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) uint __ovld __conv intel_sub_group_block_read(read_write image2d_t image, int2 coord); uint2 __ovld __conv intel_sub_group_block_read2(read_write image2d_t image, int2 coord); uint4 __ovld __conv intel_sub_group_block_read4(read_write image2d_t image, int2 coord); uint8 __ovld __conv intel_sub_group_block_read8(read_write image2d_t image, int2 coord); -#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__opencl_c_read_write_images) uint __ovld __conv intel_sub_group_block_read( const __global uint* p ); uint2 __ovld __conv intel_sub_group_block_read2( const __global uint* p ); uint4 __ovld __conv intel_sub_group_block_read4( const __global uint* p ); uint8 __ovld __conv intel_sub_group_block_read8( const __global uint* p ); +#if defined(__opencl_c_images) void __ovld __conv intel_sub_group_block_write(write_only image2d_t image, int2 coord, uint data); void __ovld __conv intel_sub_group_block_write2(write_only image2d_t image, int2 coord, uint2 data); void __ovld __conv intel_sub_group_block_write4(write_only image2d_t image, int2 coord, uint4 data); void __ovld __conv intel_sub_group_block_write8(write_only image2d_t image, int2 coord, uint8 data); +#endif // defined(__opencl_c_images) -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) void __ovld __conv intel_sub_group_block_write(read_write image2d_t image, int2 coord, uint data); void __ovld __conv intel_sub_group_block_write2(read_write image2d_t image, int2 coord, uint2 data); void __ovld __conv intel_sub_group_block_write4(read_write image2d_t image, int2 coord, uint4 data); void __ovld __conv intel_sub_group_block_write8(read_write image2d_t image, int2 coord, uint8 data); -#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__opencl_c_read_write_images) void __ovld __conv intel_sub_group_block_write( __global uint* p, uint data ); void __ovld __conv intel_sub_group_block_write2( __global uint* p, uint2 data ); @@ -17712,68 +17718,76 @@ ushort __ovld __conv intel_sub_group_scan_inclusive_min( ushort x ); short __ovld __conv intel_sub_group_scan_inclusive_max( short x ); ushort __ovld __conv intel_sub_group_scan_inclusive_max( ushort x ); +#if defined(__opencl_c_images) uint __ovld __conv intel_sub_group_block_read_ui( read_only image2d_t image, int2 byte_coord ); uint2 __ovld __conv intel_sub_group_block_read_ui2( read_only image2d_t image, int2 byte_coord ); uint4 __ovld __conv intel_sub_group_block_read_ui4( read_only image2d_t image, int2 byte_coord ); uint8 __ovld __conv intel_sub_group_block_read_ui8( read_only image2d_t image, int2 byte_coord ); +#endif // defined(__opencl_c_images) -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) uint __ovld __conv intel_sub_group_block_read_ui( read_write image2d_t image, int2 byte_coord ); uint2 __ovld __conv intel_sub_group_block_read_ui2( read_write image2d_t image, int2 byte_coord ); uint4 __ovld __conv intel_sub_group_block_read_ui4( read_write image2d_t image, int2 byte_coord ); uint8 __ovld __conv intel_sub_group_block_read_ui8( read_write image2d_t image, int2 byte_coord ); -#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__opencl_c_read_write_images) uint __ovld __conv intel_sub_group_block_read_ui( const __global uint* p ); uint2 __ovld __conv intel_sub_group_block_read_ui2( const __global uint* p ); uint4 __ovld __conv intel_sub_group_block_read_ui4( const __global uint* p ); uint8 __ovld __conv intel_sub_group_block_read_ui8( const __global uint* p ); +#if defined(__opencl_c_images) void __ovld __conv intel_sub_group_block_write_ui( read_only image2d_t image, int2 byte_coord, uint data ); void __ovld __conv intel_sub_group_block_write_ui2( read_only image2d_t image, int2 byte_coord, uint2 data ); void __ovld __conv intel_sub_group_block_write_ui4( read_only image2d_t image, int2 byte_coord, uint4 data ); void __ovld __conv intel_sub_group_block_write_ui8( read_only image2d_t image, int2 byte_coord, uint8 data ); +#endif //defined(__opencl_c_images) -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) void __ovld __conv intel_sub_group_block_write_ui( read_write image2d_t image, int2 byte_coord, uint data ); void __ovld __conv intel_sub_group_block_write_ui2( read_write image2d_t image, int2 byte_coord, uint2 data ); void __ovld __conv intel_sub_group_block_write_ui4( read_write image2d_t image, int2 byte_coord, uint4 data ); void __ovld __conv intel_sub_group_block_write_ui8( read_write image2d_t image, int2 byte_coord, uint8 data ); -#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__opencl_c_read_write_images) void __ovld __conv intel_sub_group_block_write_ui( __global uint* p, uint data ); void __ovld __conv intel_sub_group_block_write_ui2( __global uint* p, uint2 data ); void __ovld __conv intel_sub_group_block_write_ui4( __global uint* p, uint4 data ); void __ovld __conv intel_sub_group_block_write_ui8( __global uint* p, uint8 data ); +#if defined(__opencl_c_images) ushort __ovld __conv intel_sub_group_block_read_us( read_only image2d_t image, int2 coord ); ushort2 __ovld __conv intel_sub_group_block_read_us2( read_only image2d_t image, int2 coord ); ushort4 __ovld __conv intel_sub_group_block_read_us4( read_only image2d_t image, int2 coord ); ushort8 __ovld __conv intel_sub_group_block_read_us8( read_only image2d_t image, int2 coord ); +#endif // defined(__opencl_c_images) -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) ushort __ovld __conv intel_sub_group_block_read_us(read_write image2d_t image, int2 coord); ushort2 __ovld __conv intel_sub_group_block_read_us2(read_write image2d_t image, int2 coord); ushort4 __ovld __conv intel_sub_group_block_read_us4(read_write image2d_t image, int2 coord); ushort8 __ovld __conv intel_sub_group_block_read_us8(read_write image2d_t image, int2 coord); -#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__opencl_c_read_write_images) ushort __ovld __conv intel_sub_group_block_read_us( const __global ushort* p ); ushort2 __ovld __conv intel_sub_group_block_read_us2( const __global ushort* p ); ushort4 __ovld __conv intel_sub_group_block_read_us4( const __global ushort* p ); ushort8 __ovld __conv intel_sub_group_block_read_us8( const __global ushort* p ); +#if defined(__opencl_c_images) void __ovld __conv intel_sub_group_block_write_us(write_only image2d_t image, int2 coord, ushort data); void __ovld __conv intel_sub_group_block_write_us2(write_only image2d_t image, int2 coord, ushort2 data); void __ovld __conv intel_sub_group_block_write_us4(write_only image2d_t image, int2 coord, ushort4 data); void __ovld __conv intel_sub_group_block_write_us8(write_only image2d_t image, int2 coord, ushort8 data); +#endif // defined(__opencl_c_images) -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_read_write_images) void __ovld __conv intel_sub_group_block_write_us(read_write image2d_t image, int2 coord, ushort data); void __ovld __conv intel_sub_group_block_write_us2(read_write image2d_t image, int2 coord, ushort2 data); void __ovld __conv intel_sub_group_block_write_us4(read_write image2d_t image, int2 coord, ushort4 data); void __ovld __conv intel_sub_group_block_write_us8(read_write image2d_t image, int2 coord, ushort8 data); -#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__opencl_c_read_write_images) void __ovld __conv intel_sub_group_block_write_us( __global ushort* p, ushort data ); void __ovld __conv intel_sub_group_block_write_us2( __global ushort* p, ushort2 data ); @@ -17891,6 +17905,7 @@ short2 __ovld intel_sub_group_avc_ime_adjust_ref_offset( short2 ref_offset, ushort2 src_coord, ushort2 ref_window_size, ushort2 image_size); +#if defined(__opencl_c_images) intel_sub_group_avc_ime_result_t __ovld intel_sub_group_avc_ime_evaluate_with_single_reference( read_only image2d_t src_image, read_only image2d_t ref_image, @@ -17931,6 +17946,7 @@ intel_sub_group_avc_ime_evaluate_with_dual_reference_streaminout( read_only image2d_t bwd_ref_image, sampler_t vme_media_sampler, intel_sub_group_avc_ime_payload_t payload, intel_sub_group_avc_ime_dual_reference_streamin_t streamin_components); +#endif intel_sub_group_avc_ime_single_reference_streamin_t __ovld intel_sub_group_avc_ime_get_single_reference_streamin( @@ -17995,6 +18011,7 @@ intel_sub_group_avc_ref_payload_t __ovld intel_sub_group_avc_ref_set_bilinear_filter_enable( intel_sub_group_avc_ref_payload_t payload); +#if defined(__opencl_c_images) intel_sub_group_avc_ref_result_t __ovld intel_sub_group_avc_ref_evaluate_with_single_reference( read_only image2d_t src_image, read_only image2d_t ref_image, @@ -18013,6 +18030,7 @@ intel_sub_group_avc_ref_evaluate_with_multi_reference( read_only image2d_t src_image, uint packed_reference_ids, uchar packed_reference_field_polarities, sampler_t vme_media_sampler, intel_sub_group_avc_ref_payload_t payload); +#endif //defined(__opencl_c_images) // SIC built-in functions intel_sub_group_avc_sic_payload_t __ovld @@ -18063,6 +18081,7 @@ intel_sub_group_avc_sic_set_block_based_raw_skip_sad( uchar block_based_skip_type, intel_sub_group_avc_sic_payload_t payload); +#if defined(__opencl_c_images) intel_sub_group_avc_sic_result_t __ovld intel_sub_group_avc_sic_evaluate_ipe( read_only image2d_t src_image, sampler_t vme_media_sampler, @@ -18085,6 +18104,7 @@ intel_sub_group_avc_sic_evaluate_with_multi_reference( read_only image2d_t src_image, uint packed_reference_ids, uchar packed_reference_field_polarities, sampler_t vme_media_sampler, intel_sub_group_avc_sic_payload_t payload); +#endif //defined(__opencl_c_images) uchar __ovld intel_sub_group_avc_sic_get_ipe_luma_shape( intel_sub_group_avc_sic_result_t result); diff --git a/clang/lib/Headers/smmintrin.h b/clang/lib/Headers/smmintrin.h index 710e55aaa120..0df59c5fcc59 100644 --- a/clang/lib/Headers/smmintrin.h +++ b/clang/lib/Headers/smmintrin.h @@ -668,7 +668,7 @@ _mm_stream_load_si128 (__m128i const *__V) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_min_epi8 (__m128i __V1, __m128i __V2) { - return (__m128i) __builtin_ia32_pminsb128 ((__v16qi) __V1, (__v16qi) __V2); + return (__m128i) __builtin_elementwise_min((__v16qs) __V1, (__v16qs) __V2); } /// Compares the corresponding elements of two 128-bit vectors of @@ -687,7 +687,7 @@ _mm_min_epi8 (__m128i __V1, __m128i __V2) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_max_epi8 (__m128i __V1, __m128i __V2) { - return (__m128i) __builtin_ia32_pmaxsb128 ((__v16qi) __V1, (__v16qi) __V2); + return (__m128i) __builtin_elementwise_max((__v16qs) __V1, (__v16qs) __V2); } /// Compares the corresponding elements of two 128-bit vectors of @@ -706,7 +706,7 @@ _mm_max_epi8 (__m128i __V1, __m128i __V2) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_min_epu16 (__m128i __V1, __m128i __V2) { - return (__m128i) __builtin_ia32_pminuw128 ((__v8hi) __V1, (__v8hi) __V2); + return (__m128i) __builtin_elementwise_min((__v8hu) __V1, (__v8hu) __V2); } /// Compares the corresponding elements of two 128-bit vectors of @@ -725,7 +725,7 @@ _mm_min_epu16 (__m128i __V1, __m128i __V2) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_max_epu16 (__m128i __V1, __m128i __V2) { - return (__m128i) __builtin_ia32_pmaxuw128 ((__v8hi) __V1, (__v8hi) __V2); + return (__m128i) __builtin_elementwise_max((__v8hu) __V1, (__v8hu) __V2); } /// Compares the corresponding elements of two 128-bit vectors of @@ -744,7 +744,7 @@ _mm_max_epu16 (__m128i __V1, __m128i __V2) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_min_epi32 (__m128i __V1, __m128i __V2) { - return (__m128i) __builtin_ia32_pminsd128 ((__v4si) __V1, (__v4si) __V2); + return (__m128i) __builtin_elementwise_min((__v4si) __V1, (__v4si) __V2); } /// Compares the corresponding elements of two 128-bit vectors of @@ -763,7 +763,7 @@ _mm_min_epi32 (__m128i __V1, __m128i __V2) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_max_epi32 (__m128i __V1, __m128i __V2) { - return (__m128i) __builtin_ia32_pmaxsd128 ((__v4si) __V1, (__v4si) __V2); + return (__m128i) __builtin_elementwise_max((__v4si) __V1, (__v4si) __V2); } /// Compares the corresponding elements of two 128-bit vectors of @@ -782,7 +782,7 @@ _mm_max_epi32 (__m128i __V1, __m128i __V2) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_min_epu32 (__m128i __V1, __m128i __V2) { - return (__m128i) __builtin_ia32_pminud128((__v4si) __V1, (__v4si) __V2); + return (__m128i) __builtin_elementwise_min((__v4su) __V1, (__v4su) __V2); } /// Compares the corresponding elements of two 128-bit vectors of @@ -801,7 +801,7 @@ _mm_min_epu32 (__m128i __V1, __m128i __V2) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_max_epu32 (__m128i __V1, __m128i __V2) { - return (__m128i) __builtin_ia32_pmaxud128((__v4si) __V1, (__v4si) __V2); + return (__m128i) __builtin_elementwise_max((__v4su) __V1, (__v4su) __V2); } /* SSE4 Insertion and Extraction from XMM Register Instructions. */ diff --git a/clang/lib/Headers/stdatomic.h b/clang/lib/Headers/stdatomic.h index 1e47bcb2bacf..780bcc2dfea1 100644 --- a/clang/lib/Headers/stdatomic.h +++ b/clang/lib/Headers/stdatomic.h @@ -44,6 +44,11 @@ extern "C" { /* 7.17.2 Initialization */ #define ATOMIC_VAR_INIT(value) (value) +#if (__STDC_VERSION__ >= 201710L || __cplusplus >= 202002L) && \ + !defined(_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS) +/* ATOMIC_VAR_INIT was deprecated in C17 and C++20. */ +#pragma clang deprecated(ATOMIC_VAR_INIT) +#endif #define atomic_init __c11_atomic_init /* 7.17.3 Order and consistency */ @@ -153,6 +158,10 @@ typedef _Atomic(uintmax_t) atomic_uintmax_t; typedef struct atomic_flag { atomic_bool _Value; } atomic_flag; #define ATOMIC_FLAG_INIT { 0 } +#if __cplusplus >= 202002L && !defined(_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS) +/* ATOMIC_FLAG_INIT was deprecated in C++20 but is not deprecated in C. */ +#pragma clang deprecated(ATOMIC_FLAG_INIT) +#endif /* These should be provided by the libc implementation. */ #ifdef __cplusplus diff --git a/clang/lib/Headers/stdint.h b/clang/lib/Headers/stdint.h index 192f653e95a1..4790c25a2774 100644 --- a/clang/lib/Headers/stdint.h +++ b/clang/lib/Headers/stdint.h @@ -461,6 +461,18 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT64_MAX INT64_C( 9223372036854775807) # define INT64_MIN (-INT64_C( 9223372036854775807)-1) # define UINT64_MAX UINT64_C(18446744073709551615) +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT64_WIDTH 64 +# define INT64_WIDTH UINT64_WIDTH + +# define __UINT_LEAST64_WIDTH UINT64_WIDTH +# define __UINT_LEAST32_WIDTH UINT64_WIDTH +# define __UINT_LEAST16_WIDTH UINT64_WIDTH +# define __UINT_LEAST8_MAX UINT64_MAX +#endif /* __STDC_VERSION__ */ + # define __INT_LEAST64_MIN INT64_MIN # define __INT_LEAST64_MAX INT64_MAX # define __UINT_LEAST64_MAX UINT64_MAX @@ -482,6 +494,15 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT_FAST64_MIN __INT_LEAST64_MIN # define INT_FAST64_MAX __INT_LEAST64_MAX # define UINT_FAST64_MAX __UINT_LEAST64_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT_LEAST64_WIDTH __UINT_LEAST64_WIDTH +# define INT_LEAST64_WIDTH UINT_LEAST64_WIDTH +# define UINT_FAST64_WIDTH __UINT_LEAST64_WIDTH +# define INT_FAST64_WIDTH UINT_FAST64_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT_LEAST64_MIN */ @@ -495,6 +516,7 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT_FAST56_MIN INT56_MIN # define INT_FAST56_MAX INT56_MAX # define UINT_FAST56_MAX UINT56_MAX + # define __INT_LEAST32_MIN INT56_MIN # define __INT_LEAST32_MAX INT56_MAX # define __UINT_LEAST32_MAX UINT56_MAX @@ -504,6 +526,20 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define __INT_LEAST8_MIN INT56_MIN # define __INT_LEAST8_MAX INT56_MAX # define __UINT_LEAST8_MAX UINT56_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT56_WIDTH 56 +# define INT56_WIDTH UINT56_WIDTH +# define UINT_LEAST56_WIDTH UINT56_WIDTH +# define INT_LEAST56_WIDTH UINT_LEAST56_WIDTH +# define UINT_FAST56_WIDTH UINT56_WIDTH +# define INT_FAST56_WIDTH UINT_FAST56_WIDTH +# define __UINT_LEAST32_WIDTH UINT56_WIDTH +# define __UINT_LEAST16_WIDTH UINT56_WIDTH +# define __UINT_LEAST8_WIDTH UINT56_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT56_TYPE__ */ @@ -517,6 +553,7 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT_FAST48_MIN INT48_MIN # define INT_FAST48_MAX INT48_MAX # define UINT_FAST48_MAX UINT48_MAX + # define __INT_LEAST32_MIN INT48_MIN # define __INT_LEAST32_MAX INT48_MAX # define __UINT_LEAST32_MAX UINT48_MAX @@ -526,6 +563,20 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define __INT_LEAST8_MIN INT48_MIN # define __INT_LEAST8_MAX INT48_MAX # define __UINT_LEAST8_MAX UINT48_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +#define UINT48_WIDTH 48 +#define INT48_WIDTH UINT48_WIDTH +#define UINT_LEAST48_WIDTH UINT48_WIDTH +#define INT_LEAST48_WIDTH UINT_LEAST48_WIDTH +#define UINT_FAST48_WIDTH UINT48_WIDTH +#define INT_FAST48_WIDTH UINT_FAST48_WIDTH +#define __UINT_LEAST32_WIDTH UINT48_WIDTH +#define __UINT_LEAST16_WIDTH UINT48_WIDTH +#define __UINT_LEAST8_WIDTH UINT48_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT48_TYPE__ */ @@ -539,6 +590,7 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT_FAST40_MIN INT40_MIN # define INT_FAST40_MAX INT40_MAX # define UINT_FAST40_MAX UINT40_MAX + # define __INT_LEAST32_MIN INT40_MIN # define __INT_LEAST32_MAX INT40_MAX # define __UINT_LEAST32_MAX UINT40_MAX @@ -548,6 +600,20 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define __INT_LEAST8_MIN INT40_MIN # define __INT_LEAST8_MAX INT40_MAX # define __UINT_LEAST8_MAX UINT40_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT40_WIDTH 40 +# define INT40_WIDTH UINT40_WIDTH +# define UINT_LEAST40_WIDTH UINT40_WIDTH +# define INT_LEAST40_WIDTH UINT_LEAST40_WIDTH +# define UINT_FAST40_WIDTH UINT40_WIDTH +# define INT_FAST40_WIDTH UINT_FAST40_WIDTH +# define __UINT_LEAST32_WIDTH UINT40_WIDTH +# define __UINT_LEAST16_WIDTH UINT40_WIDTH +# define __UINT_LEAST8_WIDTH UINT40_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT40_TYPE__ */ @@ -555,6 +621,7 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT32_MAX INT32_C(2147483647) # define INT32_MIN (-INT32_C(2147483647)-1) # define UINT32_MAX UINT32_C(4294967295) + # define __INT_LEAST32_MIN INT32_MIN # define __INT_LEAST32_MAX INT32_MAX # define __UINT_LEAST32_MAX UINT32_MAX @@ -564,6 +631,16 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define __INT_LEAST8_MIN INT32_MIN # define __INT_LEAST8_MAX INT32_MAX # define __UINT_LEAST8_MAX UINT32_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT32_WIDTH 32 +# define INT32_WIDTH UINT32_WIDTH +# define __UINT_LEAST32_WIDTH UINT32_WIDTH +# define __UINT_LEAST16_WIDTH UINT32_WIDTH +# define __UINT_LEAST8_WIDTH UINT32_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT32_TYPE__ */ #ifdef __INT_LEAST32_MIN @@ -573,6 +650,15 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT_FAST32_MIN __INT_LEAST32_MIN # define INT_FAST32_MAX __INT_LEAST32_MAX # define UINT_FAST32_MAX __UINT_LEAST32_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT_LEAST32_WIDTH __UINT_LEAST32_WIDTH +# define INT_LEAST32_WIDTH UINT_LEAST32_WIDTH +# define UINT_FAST32_WIDTH __UINT_LEAST32_WIDTH +# define INT_FAST32_WIDTH UINT_FAST32_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT_LEAST32_MIN */ @@ -586,12 +672,26 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT_FAST24_MIN INT24_MIN # define INT_FAST24_MAX INT24_MAX # define UINT_FAST24_MAX UINT24_MAX + # define __INT_LEAST16_MIN INT24_MIN # define __INT_LEAST16_MAX INT24_MAX # define __UINT_LEAST16_MAX UINT24_MAX # define __INT_LEAST8_MIN INT24_MIN # define __INT_LEAST8_MAX INT24_MAX # define __UINT_LEAST8_MAX UINT24_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT24_WIDTH 24 +# define INT24_WIDTH UINT24_WIDTH +# define UINT_LEAST24_WIDTH UINT24_WIDTH +# define INT_LEAST24_WIDTH UINT_LEAST24_WIDTH +# define UINT_FAST24_WIDTH UINT24_WIDTH +# define INT_FAST24_WIDTH UINT_FAST24_WIDTH +# define __UINT_LEAST16_WIDTH UINT24_WIDTH +# define __UINT_LEAST8_WIDTH UINT24_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT24_TYPE__ */ @@ -599,12 +699,22 @@ typedef __UINTMAX_TYPE__ uintmax_t; #define INT16_MAX INT16_C(32767) #define INT16_MIN (-INT16_C(32767)-1) #define UINT16_MAX UINT16_C(65535) + # define __INT_LEAST16_MIN INT16_MIN # define __INT_LEAST16_MAX INT16_MAX # define __UINT_LEAST16_MAX UINT16_MAX # define __INT_LEAST8_MIN INT16_MIN # define __INT_LEAST8_MAX INT16_MAX # define __UINT_LEAST8_MAX UINT16_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT16_WIDTH 16 +# define INT16_WIDTH UINT16_WIDTH +# define __UINT_LEAST16_WIDTH UINT16_WIDTH +# define __UINT_LEAST8_WIDTH UINT16_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT16_TYPE__ */ #ifdef __INT_LEAST16_MIN @@ -614,6 +724,15 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT_FAST16_MIN __INT_LEAST16_MIN # define INT_FAST16_MAX __INT_LEAST16_MAX # define UINT_FAST16_MAX __UINT_LEAST16_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT_LEAST16_WIDTH __UINT_LEAST16_WIDTH +# define INT_LEAST16_WIDTH UINT_LEAST16_WIDTH +# define UINT_FAST16_WIDTH __UINT_LEAST16_WIDTH +# define INT_FAST16_WIDTH UINT_FAST16_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT_LEAST16_MIN */ @@ -621,9 +740,18 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT8_MAX INT8_C(127) # define INT8_MIN (-INT8_C(127)-1) # define UINT8_MAX UINT8_C(255) + # define __INT_LEAST8_MIN INT8_MIN # define __INT_LEAST8_MAX INT8_MAX # define __UINT_LEAST8_MAX UINT8_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT8_WIDTH 8 +# define INT8_WIDTH UINT8_WIDTH +# define __UINT_LEAST8_WIDTH UINT8_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT8_TYPE__ */ #ifdef __INT_LEAST8_MIN @@ -633,6 +761,15 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define INT_FAST8_MIN __INT_LEAST8_MIN # define INT_FAST8_MAX __INT_LEAST8_MAX # define UINT_FAST8_MAX __UINT_LEAST8_MAX + +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +# define UINT_LEAST8_WIDTH __UINT_LEAST8_WIDTH +# define INT_LEAST8_WIDTH UINT_LEAST8_WIDTH +# define UINT_FAST8_WIDTH __UINT_LEAST8_WIDTH +# define INT_FAST8_WIDTH UINT_FAST8_WIDTH +#endif /* __STDC_VERSION__ */ #endif /* __INT_LEAST8_MIN */ /* Some utility macros */ @@ -652,6 +789,16 @@ typedef __UINTMAX_TYPE__ uintmax_t; #define PTRDIFF_MAX __PTRDIFF_MAX__ #define SIZE_MAX __SIZE_MAX__ +/* C2x 7.20.2.4 Width of integer types capable of holding object pointers. */ +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +/* NB: The C standard requires that these be the same value, but the compiler + exposes separate internal width macros. */ +#define INTPTR_WIDTH __INTPTR_WIDTH__ +#define UINTPTR_WIDTH __UINTPTR_WIDTH__ +#endif + /* ISO9899:2011 7.20 (C11 Annex K): Define RSIZE_MAX if __STDC_WANT_LIB_EXT1__ * is enabled. */ #if defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1 @@ -663,6 +810,16 @@ typedef __UINTMAX_TYPE__ uintmax_t; #define INTMAX_MAX __INTMAX_MAX__ #define UINTMAX_MAX __UINTMAX_MAX__ +/* C2x 7.20.2.5 Width of greatest-width integer types. */ +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +/* NB: The C standard requires that these be the same value, but the compiler + exposes separate internal width macros. */ +#define INTMAX_WIDTH __INTMAX_WIDTH__ +#define UINTMAX_WIDTH __UINTMAX_WIDTH__ +#endif + /* C99 7.18.3 Limits of other integer types. */ #define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__) #define SIG_ATOMIC_MAX __INTN_MAX(__SIG_ATOMIC_WIDTH__) @@ -689,5 +846,16 @@ typedef __UINTMAX_TYPE__ uintmax_t; #define INTMAX_C(v) __int_c(v, __INTMAX_C_SUFFIX__) #define UINTMAX_C(v) __int_c(v, __UINTMAX_C_SUFFIX__) +/* C2x 7.20.3.x Width of other integer types. */ +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if __STDC_VERSION__ >= 202000L +#define PTRDIFF_WIDTH __PTRDIFF_WIDTH__ +#define SIG_ATOMIC_WIDTH __SIG_ATOMIC_WIDTH__ +#define SIZE_WIDTH __SIZE_WIDTH__ +#define WCHAR_WIDTH __WCHAR_WIDTH__ +#define WINT_WIDTH __WINT_WIDTH__ +#endif + #endif /* __STDC_HOSTED__ */ #endif /* __CLANG_STDINT_H */ diff --git a/clang/lib/Headers/tmmintrin.h b/clang/lib/Headers/tmmintrin.h index bcffa8187801..cb9be2349de5 100644 --- a/clang/lib/Headers/tmmintrin.h +++ b/clang/lib/Headers/tmmintrin.h @@ -53,7 +53,7 @@ _mm_abs_pi8(__m64 __a) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_abs_epi8(__m128i __a) { - return (__m128i)__builtin_ia32_pabsb128((__v16qi)__a); + return (__m128i)__builtin_elementwise_abs((__v16qs)__a); } /// Computes the absolute value of each of the packed 16-bit signed @@ -89,7 +89,7 @@ _mm_abs_pi16(__m64 __a) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_abs_epi16(__m128i __a) { - return (__m128i)__builtin_ia32_pabsw128((__v8hi)__a); + return (__m128i)__builtin_elementwise_abs((__v8hi)__a); } /// Computes the absolute value of each of the packed 32-bit signed @@ -125,7 +125,7 @@ _mm_abs_pi32(__m64 __a) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_abs_epi32(__m128i __a) { - return (__m128i)__builtin_ia32_pabsd128((__v4si)__a); + return (__m128i)__builtin_elementwise_abs((__v4si)__a); } /// Concatenates the two 128-bit integer vector operands, and diff --git a/clang/lib/Headers/vaesintrin.h b/clang/lib/Headers/vaesintrin.h index f3c0807bb94a..294dcff2addd 100644 --- a/clang/lib/Headers/vaesintrin.h +++ b/clang/lib/Headers/vaesintrin.h @@ -82,4 +82,4 @@ static __inline__ __m512i __DEFAULT_FN_ATTRS_F #undef __DEFAULT_FN_ATTRS #undef __DEFAULT_FN_ATTRS_F -#endif +#endif // __VAESINTRIN_H diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index 84eabc3a210f..4ade8b8bb074 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -256,7 +256,7 @@ IncrementalParser::Parse(llvm::StringRef input) { /*LoadedOffset=*/0, NewLoc); // NewLoc only used for diags. - if (PP.EnterSourceFile(FID, /*DirLookup=*/0, NewLoc)) + if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc)) return llvm::make_error<llvm::StringError>("Parsing failed. " "Cannot enter source file.", std::error_code()); diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h index e5ce798025d9..d1f454f21239 100644 --- a/clang/lib/Interpreter/IncrementalParser.h +++ b/clang/lib/Interpreter/IncrementalParser.h @@ -30,9 +30,6 @@ class LLVMContext; namespace clang { class ASTConsumer; class CompilerInstance; -class CodeGenerator; -class DeclGroupRef; -class FrontendAction; class IncrementalAction; class Parser; diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index a0b60118a1a8..39c125c395ef 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -29,6 +29,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Capacity.h" #include "llvm/Support/Errc.h" @@ -89,16 +90,10 @@ HeaderSearch::HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts, void HeaderSearch::PrintStats() { llvm::errs() << "\n*** HeaderSearch Stats:\n" << FileInfo.size() << " files tracked.\n"; - unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0; - for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) { + unsigned NumOnceOnlyFiles = 0; + for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) NumOnceOnlyFiles += (FileInfo[i].isPragmaOnce || FileInfo[i].isImport); - if (MaxNumIncludes < FileInfo[i].NumIncludes) - MaxNumIncludes = FileInfo[i].NumIncludes; - NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1; - } - llvm::errs() << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n" - << " " << NumSingleIncludedFiles << " included exactly once.\n" - << " " << MaxNumIncludes << " max times a file is included.\n"; + llvm::errs() << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n"; llvm::errs() << " " << NumIncluded << " #include/#include_next/#import.\n" << " " << NumMultiIncludeFileOptzn @@ -108,6 +103,30 @@ void HeaderSearch::PrintStats() { << NumSubFrameworkLookups << " subframework lookups.\n"; } +void HeaderSearch::SetSearchPaths( + std::vector<DirectoryLookup> dirs, unsigned int angledDirIdx, + unsigned int systemDirIdx, bool noCurDirSearch, + llvm::DenseMap<unsigned int, unsigned int> searchDirToHSEntry) { + assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() && + "Directory indices are unordered"); + SearchDirs = std::move(dirs); + SearchDirsUsage.assign(SearchDirs.size(), false); + AngledDirIdx = angledDirIdx; + SystemDirIdx = systemDirIdx; + NoCurDirSearch = noCurDirSearch; + SearchDirToHSEntry = std::move(searchDirToHSEntry); + //LookupFileCache.clear(); +} + +void HeaderSearch::AddSearchPath(const DirectoryLookup &dir, bool isAngled) { + unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx; + SearchDirs.insert(SearchDirs.begin() + idx, dir); + SearchDirsUsage.insert(SearchDirsUsage.begin() + idx, false); + if (!isAngled) + AngledDirIdx++; + SystemDirIdx++; +} + std::vector<bool> HeaderSearch::computeUserEntryUsage() const { std::vector<bool> UserEntryUsage(HSOpts->UserEntries.size()); for (unsigned I = 0, E = SearchDirsUsage.size(); I < E; ++I) { @@ -720,7 +739,8 @@ static const char *copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) { } static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader, - SmallVectorImpl<char> &FrameworkName) { + SmallVectorImpl<char> &FrameworkName, + SmallVectorImpl<char> &IncludeSpelling) { using namespace llvm::sys; path::const_iterator I = path::begin(Path); path::const_iterator E = path::end(Path); @@ -736,15 +756,22 @@ static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader, // and some other variations among these lines. int FoundComp = 0; while (I != E) { - if (*I == "Headers") + if (*I == "Headers") { ++FoundComp; - if (I->endswith(".framework")) { - FrameworkName.append(I->begin(), I->end()); - ++FoundComp; - } - if (*I == "PrivateHeaders") { + } else if (*I == "PrivateHeaders") { ++FoundComp; IsPrivateHeader = true; + } else if (I->endswith(".framework")) { + StringRef Name = I->drop_back(10); // Drop .framework + // Need to reset the strings and counter to support nested frameworks. + FrameworkName.clear(); + FrameworkName.append(Name.begin(), Name.end()); + IncludeSpelling.clear(); + IncludeSpelling.append(Name.begin(), Name.end()); + FoundComp = 1; + } else if (FoundComp >= 2) { + IncludeSpelling.push_back('/'); + IncludeSpelling.append(I->begin(), I->end()); } ++I; } @@ -759,20 +786,24 @@ diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc, bool FoundByHeaderMap = false) { bool IsIncluderPrivateHeader = false; SmallString<128> FromFramework, ToFramework; - if (!isFrameworkStylePath(Includer, IsIncluderPrivateHeader, FromFramework)) + SmallString<128> FromIncludeSpelling, ToIncludeSpelling; + if (!isFrameworkStylePath(Includer, IsIncluderPrivateHeader, FromFramework, + FromIncludeSpelling)) return; bool IsIncludeePrivateHeader = false; - bool IsIncludeeInFramework = isFrameworkStylePath( - IncludeFE->getName(), IsIncludeePrivateHeader, ToFramework); + bool IsIncludeeInFramework = + isFrameworkStylePath(IncludeFE->getName(), IsIncludeePrivateHeader, + ToFramework, ToIncludeSpelling); if (!isAngled && !FoundByHeaderMap) { SmallString<128> NewInclude("<"); if (IsIncludeeInFramework) { - NewInclude += ToFramework.str().drop_back(10); // drop .framework - NewInclude += "/"; + NewInclude += ToIncludeSpelling; + NewInclude += ">"; + } else { + NewInclude += IncludeFilename; + NewInclude += ">"; } - NewInclude += IncludeFilename; - NewInclude += ">"; Diags.Report(IncludeLoc, diag::warn_quoted_include_in_framework_header) << IncludeFilename << FixItHint::CreateReplacement(IncludeLoc, NewInclude); @@ -794,12 +825,15 @@ diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc, /// search is needed. Microsoft mode will pass all \#including files. Optional<FileEntryRef> HeaderSearch::LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, - const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, + const DirectoryLookup *FromDir, const DirectoryLookup **CurDirArg, ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool *IsFrameworkFound, bool SkipCache, bool BuildSystemModule) { + const DirectoryLookup *CurDirLocal = nullptr; + const DirectoryLookup *&CurDir = CurDirArg ? *CurDirArg : CurDirLocal; + if (IsMapped) *IsMapped = false; @@ -1046,7 +1080,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile( ScratchFilename += Filename; Optional<FileEntryRef> File = LookupFile( - ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir, + ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, &CurDir, Includers.front(), SearchPath, RelativePath, RequestingModule, SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr); @@ -1203,7 +1237,6 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI, HFI.isImport |= OtherHFI.isImport; HFI.isPragmaOnce |= OtherHFI.isPragmaOnce; HFI.isModuleHeader |= OtherHFI.isModuleHeader; - HFI.NumIncludes += OtherHFI.NumIncludes; if (!HFI.ControllingMacro && !HFI.ControllingMacroID) { HFI.ControllingMacro = OtherHFI.ControllingMacro; @@ -1364,7 +1397,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, FileInfo.isImport = true; // Has this already been #import'ed or #include'd? - if (FileInfo.NumIncludes && !TryEnterImported()) + if (PP.alreadyIncluded(File) && !TryEnterImported()) return false; } else { // Otherwise, if this is a #include of a file that was previously #import'd @@ -1387,10 +1420,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, } } - // Increment the number of times this file has been included. - ++FileInfo.NumIncludes; - - IsFirstIncludeOfFile = FileInfo.NumIncludes == 1; + IsFirstIncludeOfFile = PP.markIncluded(File); return true; } @@ -1779,11 +1809,8 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) { } // Populate the list of modules. - for (ModuleMap::module_iterator M = ModMap.module_begin(), - MEnd = ModMap.module_end(); - M != MEnd; ++M) { - Modules.push_back(M->getValue()); - } + llvm::transform(ModMap.modules(), std::back_inserter(Modules), + [](const auto &NameAndMod) { return NameAndMod.second; }); } void HeaderSearch::loadTopLevelSystemModules() { @@ -1843,9 +1870,9 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics( using namespace llvm::sys; unsigned BestPrefixLength = 0; - // Checks whether Dir and File shares a common prefix, if they do and that's - // the longest prefix we've seen so for it returns true and updates the - // BestPrefixLength accordingly. + // Checks whether `Dir` is a strict path prefix of `File`. If so and that's + // the longest prefix we've seen so for it, returns true and updates the + // `BestPrefixLength` accordingly. auto CheckDir = [&](llvm::StringRef Dir) -> bool { llvm::SmallString<32> DirPath(Dir.begin(), Dir.end()); if (!WorkingDir.empty() && !path::is_absolute(Dir)) @@ -1880,26 +1907,48 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics( path::is_separator(NI->front()) && path::is_separator(DI->front())) continue; + // Special case Apple .sdk folders since the search path is typically a + // symlink like `iPhoneSimulator14.5.sdk` while the file is instead + // located in `iPhoneSimulator.sdk` (the real folder). + if (NI->endswith(".sdk") && DI->endswith(".sdk")) { + StringRef NBasename = path::stem(*NI); + StringRef DBasename = path::stem(*DI); + if (DBasename.startswith(NBasename)) + continue; + } + if (*NI != *DI) break; } return false; }; + bool BestPrefixIsFramework = false; for (unsigned I = 0; I != SearchDirs.size(); ++I) { - // FIXME: Support this search within frameworks. - if (!SearchDirs[I].isNormalDir()) - continue; - - StringRef Dir = SearchDirs[I].getDir()->getName(); - if (CheckDir(Dir) && IsSystem) - *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false; + if (SearchDirs[I].isNormalDir()) { + StringRef Dir = SearchDirs[I].getDir()->getName(); + if (CheckDir(Dir)) { + if (IsSystem) + *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false; + BestPrefixIsFramework = false; + } + } else if (SearchDirs[I].isFramework()) { + StringRef Dir = SearchDirs[I].getFrameworkDir()->getName(); + if (CheckDir(Dir)) { + if (IsSystem) + *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false; + BestPrefixIsFramework = true; + } + } } // Try to shorten include path using TUs directory, if we couldn't find any // suitable prefix in include search paths. - if (!BestPrefixLength && CheckDir(path::parent_path(MainFile)) && IsSystem) - *IsSystem = false; + if (!BestPrefixLength && CheckDir(path::parent_path(MainFile))) { + if (IsSystem) + *IsSystem = false; + BestPrefixIsFramework = false; + } // Try resolving resulting filename via reverse search in header maps, // key from header name is user prefered name for the include file. @@ -1912,8 +1961,19 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics( SearchDirs[I].getHeaderMap()->reverseLookupFilename(Filename); if (!SpelledFilename.empty()) { Filename = SpelledFilename; + BestPrefixIsFramework = false; break; } } + + // If the best prefix is a framework path, we need to compute the proper + // include spelling for the framework header. + bool IsPrivateHeader; + SmallString<128> FrameworkName, IncludeSpelling; + if (BestPrefixIsFramework && + isFrameworkStylePath(Filename, IsPrivateHeader, FrameworkName, + IncludeSpelling)) { + Filename = IncludeSpelling; + } return path::convert_to_slash(Filename); } diff --git a/clang/lib/Frontend/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp index ed1314f3b03d..ec7b1505c7bf 100644 --- a/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/clang/lib/Lex/InitHeaderSearch.cpp @@ -10,11 +10,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" #include "clang/Config/config.h" // C_INCLUDE_DIRS -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderMap.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" @@ -354,7 +353,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, break; case llvm::Triple::PS4: { // <isysroot> gets prepended later in AddPath(). - std::string BaseSDKPath = ""; + std::string BaseSDKPath; if (!HasSysroot) { const char *envValue = getenv("SCE_ORBIS_SDK_DIR"); if (envValue) diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 38467a1835d0..89e89c7c1f17 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -2548,9 +2548,9 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr, assert(CurPtr[0] == '\n' || CurPtr[0] == '\r'); // Position of the first trigraph in the ending sequence. - const char *TrigraphPos = 0; + const char *TrigraphPos = nullptr; // Position of the first whitespace after a '\' in the ending sequence. - const char *SpacePos = 0; + const char *SpacePos = nullptr; while (true) { // Back up off the newline. diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index ef7a5351953e..f3aefdd22b51 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -818,10 +818,13 @@ Preprocessor::getHeaderToIncludeForDiagnostics(SourceLocation IncLoc, Optional<FileEntryRef> Preprocessor::LookupFile( SourceLocation FilenameLoc, StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const FileEntry *FromFile, - const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath, + const DirectoryLookup **CurDirArg, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool *IsFrameworkFound, bool SkipCache) { + const DirectoryLookup *CurDirLocal = nullptr; + const DirectoryLookup *&CurDir = CurDirArg ? *CurDirArg : CurDirLocal; + Module *RequestingModule = getModuleForLocation(FilenameLoc); bool RequestingModuleIsModuleInterface = !SourceMgr.isInMainFile(FilenameLoc); @@ -877,7 +880,7 @@ Optional<FileEntryRef> Preprocessor::LookupFile( const DirectoryLookup *TmpCurDir = CurDir; const DirectoryLookup *TmpFromDir = nullptr; while (Optional<FileEntryRef> FE = HeaderInfo.LookupFile( - Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir, + Filename, FilenameLoc, isAngled, TmpFromDir, &TmpCurDir, Includers, SearchPath, RelativePath, RequestingModule, SuggestedModule, /*IsMapped=*/nullptr, /*IsFrameworkFound=*/nullptr, SkipCache)) { @@ -895,7 +898,7 @@ Optional<FileEntryRef> Preprocessor::LookupFile( // Do a standard file entry lookup. Optional<FileEntryRef> FE = HeaderInfo.LookupFile( - Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath, + Filename, FilenameLoc, isAngled, FromDir, &CurDir, Includers, SearchPath, RelativePath, RequestingModule, SuggestedModule, IsMapped, IsFrameworkFound, SkipCache, BuildSystemModule); if (FE) { @@ -1827,7 +1830,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, } Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport( - const DirectoryLookup *&CurDir, StringRef& Filename, + const DirectoryLookup **CurDir, StringRef& Filename, SourceLocation FilenameLoc, CharSourceRange FilenameRange, const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl, bool &IsMapped, const DirectoryLookup *LookupFrom, @@ -2028,7 +2031,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( } Optional<FileEntryRef> File = LookupHeaderIncludeOrImport( - CurDir, Filename, FilenameLoc, FilenameRange, FilenameTok, + &CurDir, Filename, FilenameLoc, FilenameRange, FilenameTok, IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile, LookupFilename, RelativePath, SearchPath, SuggestedModule, isAngled); @@ -2055,7 +2058,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( // include cycle. Don't enter already processed files again as it can lead to // reaching the max allowed include depth again. if (Action == Enter && HasReachedMaxIncludeDepth && File && - HeaderInfo.getFileInfo(&File->getFileEntry()).NumIncludes) + alreadyIncluded(*File)) Action = IncludeLimitReached; // Determine whether we should try to import the module for this #include, if diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index cfee7a3c2513..f6c95a8b67c6 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1228,10 +1228,9 @@ static bool EvaluateHasIncludeCommon(Token &Tok, return false; // Search include directories. - const DirectoryLookup *CurDir; Optional<FileEntryRef> File = PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile, - CurDir, nullptr, nullptr, nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (PPCallbacks *Callbacks = PP.getPPCallbacks()) { SrcMgr::CharacteristicKind FileType = SrcMgr::C_User; diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 67daa5841983..eb7e7cbc4714 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -526,9 +526,8 @@ static llvm::Optional<Token> LexHeader(Preprocessor &PP, return llvm::None; // Search include directories for this file. - const DirectoryLookup *CurDir; File = PP.LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr, - nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (!File) { if (!SuppressIncludeNotFoundError) diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index b026ae36fc0f..3c338a2b8123 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -549,7 +549,7 @@ void Preprocessor::EnterMainSourceFile() { // Tell the header info that the main file was entered. If the file is later // #imported, it won't be re-entered. if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID)) - HeaderInfo.IncrementIncludeCount(FE); + markIncluded(FE); } // Preprocess Predefines to populate the initial preprocessor state. @@ -566,11 +566,10 @@ void Preprocessor::EnterMainSourceFile() { if (!PPOpts->PCHThroughHeader.empty()) { // Lookup and save the FileID for the through header. If it isn't found // in the search path, it's a fatal error. - const DirectoryLookup *CurDir; Optional<FileEntryRef> File = LookupFile( SourceLocation(), PPOpts->PCHThroughHeader, - /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, CurDir, - /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, + /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, + /*CurDir=*/nullptr, /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, /*IsFrameworkFound=*/nullptr); if (!File) { diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index 19cddc69ebfc..7330c2b7593d 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -140,8 +140,22 @@ NamedDecl *Parser::ParseCXXInlineMethodDef( // function body. if (ConsumeAndStoreFunctionPrologue(Toks)) { // We didn't find the left-brace we expected after the - // constructor initializer; we already printed an error, and it's likely - // impossible to recover, so don't try to parse this method later. + // constructor initializer. + + // If we're code-completing and the completion point was in the broken + // initializer, we want to parse it even though that will fail. + if (PP.isCodeCompletionEnabled() && + llvm::any_of(Toks, [](const Token &Tok) { + return Tok.is(tok::code_completion); + })) { + // If we gave up at the completion point, the initializer list was + // likely truncated, so don't eat more tokens. We'll hit some extra + // errors, but they should be ignored in code completion. + return FnD; + } + + // We already printed an error, and it's likely impossible to recover, + // so don't try to parse this method later. // Skip over the rest of the decl and back to somewhere that looks // reasonable. SkipMalformedDecl(); @@ -803,7 +817,7 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, // We always want this function to consume at least one token if the first // token isn't T and if not at EOF. bool isFirstTokenConsumed = true; - while (1) { + while (true) { // If we found one of the tokens, stop and return true. if (Tok.is(T1) || Tok.is(T2)) { if (ConsumeFinalToken) { @@ -1159,7 +1173,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, unsigned AngleCount = 0; unsigned KnownTemplateCount = 0; - while (1) { + while (true) { switch (Tok.getKind()) { case tok::comma: // If we might be in a template, perform a tentative parse to check. diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0c1f88bc51d1..f21938c81689 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2419,8 +2419,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl); auto RunSignatureHelp = [&]() { QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), - ThisDecl->getLocation(), Exprs, T.getOpenLocation()); + ThisVarDecl->getType()->getCanonicalTypeInternal(), + ThisDecl->getLocation(), Exprs, T.getOpenLocation(), + /*Braced=*/false); CalledSignatureHelp = true; return PreferredType; }; @@ -2439,8 +2440,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( if (ParseExpressionList(Exprs, CommaLocs, ExpressionStarts)) { if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) { Actions.ProduceConstructorSignatureHelp( - getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), - ThisDecl->getLocation(), Exprs, T.getOpenLocation()); + ThisVarDecl->getType()->getCanonicalTypeInternal(), + ThisDecl->getLocation(), Exprs, T.getOpenLocation(), + /*Braced=*/false); CalledSignatureHelp = true; } Actions.ActOnInitializerError(ThisDecl); @@ -3078,7 +3080,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParsedAttributesWithRange attrs(AttrFactory); // We use Sema's policy to get bool macros right. PrintingPolicy Policy = Actions.getPrintingPolicy(); - while (1) { + while (true) { bool isInvalid = false; bool isStorageClass = false; const char *PrevSpec = nullptr; @@ -3574,12 +3576,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } } ConsumedEnd = Tok.getLocation(); + DS.setTypeofParensRange(Tracker.getRange()); // Even if something went wrong above, continue as if we've seen // `decltype(auto)`. isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec, DiagID, TemplateId, Policy); } else { - isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID, + isInvalid = DS.SetTypeSpecType(TST_auto, AutoLoc, PrevSpec, DiagID, TemplateId, Policy); } break; @@ -4269,7 +4272,7 @@ void Parser::ParseStructDeclaration( // Read struct-declarators until we find the semicolon. bool FirstDeclarator = true; SourceLocation CommaLoc; - while (1) { + while (true) { ParsingFieldDeclarator DeclaratorInfo(*this, DS); DeclaratorInfo.D.setCommaLoc(CommaLoc); @@ -4536,7 +4539,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, CXXScopeSpec Spec; if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/true)) return; @@ -5420,7 +5423,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) { // Parse the C++ scope specifier. CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/true)) { TPA.Revert(); return false; @@ -5578,7 +5581,7 @@ void Parser::ParseTypeQualifierListOpt( SourceLocation EndLoc; - while (1) { + while (true) { bool isInvalid = false; const char *PrevSpec = nullptr; unsigned DiagID = 0; @@ -5802,7 +5805,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, D.getContext() == DeclaratorContext::Member; CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, EnteringContext); + /*ObjectHasErrors=*/false, EnteringContext); if (SS.isNotEmpty()) { if (Tok.isNot(tok::star)) { @@ -6031,7 +6034,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.getContext() == DeclaratorContext::Member; ParseOptionalCXXScopeSpecifier( D.getCXXScopeSpec(), /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, EnteringContext); + /*ObjectHasErrors=*/false, EnteringContext); } if (D.getCXXScopeSpec().isValid()) { @@ -6270,7 +6273,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (D.hasName() && !D.getNumTypeObjects()) MaybeParseCXX11Attributes(D); - while (1) { + while (true) { if (Tok.is(tok::l_paren)) { bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration(); // Enter function-declaration scope, limiting any declarators to the diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index f5a6ffcff9e9..c08a586604b1 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -291,7 +291,7 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false, /*MayBePseudoDestructor=*/nullptr, /*IsTypename=*/false, @@ -529,7 +529,7 @@ Decl *Parser::ParseUsingDirective(DeclaratorContext Context, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false, /*MayBePseudoDestructor=*/nullptr, /*IsTypename=*/false, @@ -598,7 +598,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, // Parse nested-name-specifier. IdentifierInfo *LastII = nullptr; if (ParseOptionalCXXScopeSpecifier(D.SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false, /*MayBePseudoDtor=*/nullptr, /*IsTypename=*/false, @@ -1007,6 +1007,9 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { if (Tok.is(tok::annot_decltype)) { Result = getExprAnnotation(Tok); EndLoc = Tok.getAnnotationEndLoc(); + // Unfortunately, we don't know the LParen source location as the annotated + // token doesn't have it. + DS.setTypeofParensRange(SourceRange(SourceLocation(), EndLoc)); ConsumeAnnotationToken(); if (Result.isInvalid()) { DS.SetTypeSpecError(); @@ -1071,6 +1074,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { // Match the ')' T.consumeClose(); + DS.setTypeofParensRange(T.getRange()); if (T.getCloseLocation().isInvalid()) { DS.SetTypeSpecError(); // FIXME: this should return the location of the last token @@ -1190,7 +1194,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, // Parse optional nested-name-specifier CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false)) return true; @@ -1609,7 +1613,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, CXXScopeSpec Spec; bool HasValidSpec = true; if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, EnteringContext)) { DS.SetTypeSpecError(); HasValidSpec = false; @@ -2605,7 +2609,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Collect the scope specifier token we annotated earlier. CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false); if (SS.isInvalid()) { @@ -2905,7 +2909,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // member-declarator // member-declarator-list ',' member-declarator - while (1) { + while (true) { InClassInitStyle HasInClassInit = ICIS_NoInit; bool HasStaticInitializer = false; if (Tok.isOneOf(tok::equal, tok::l_brace) && PureSpecLoc.isInvalid()) { @@ -3674,7 +3678,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // parse '::'[opt] nested-name-specifier[opt] CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false)) return true; @@ -3740,8 +3744,8 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { if (TemplateTypeTy.isInvalid()) return QualType(); QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp( - getCurScope(), ConstructorDecl, SS, TemplateTypeTy.get(), ArgExprs, II, - T.getOpenLocation()); + ConstructorDecl, SS, TemplateTypeTy.get(), ArgExprs, II, + T.getOpenLocation(), /*Braced=*/false); CalledSignatureHelp = true; return PreferredType; }; diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 09a3842f5809..fbf79a0a8746 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -400,7 +400,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { SourceLocation ColonLoc; auto SavedType = PreferredType; - while (1) { + while (true) { // Every iteration may rely on a preferred type for the whole expression. PreferredType = SavedType; // If this token has a lower precedence than we are allowed to parse (e.g. @@ -1588,7 +1588,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // cast expression. CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false); AnnotateTemplateIdTokenAsType(SS); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, @@ -1853,7 +1853,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // parsed, see if there are any postfix-expression pieces here. SourceLocation Loc; auto SavedType = PreferredType; - while (1) { + while (true) { // Each iteration relies on preferred type for the whole expression. PreferredType = SavedType; switch (Tok.getKind()) { @@ -2019,7 +2019,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { CommaLocsTy CommaLocs; auto RunSignatureHelp = [&]() -> QualType { QualType PreferredType = Actions.ProduceCallSignatureHelp( - getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation()); + LHS.get(), ArgExprs, PT.getOpenLocation()); CalledSignatureHelp = true; return PreferredType; }; @@ -2558,7 +2558,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); // FIXME: This loop leaks the index expressions on error. - while (1) { + while (true) { if (Tok.is(tok::period)) { // offsetof-member-designator: offsetof-member-designator '.' identifier Comps.push_back(Sema::OffsetOfComponent()); @@ -3358,7 +3358,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, SmallVectorImpl<SourceLocation> &CommaLocs, llvm::function_ref<void()> ExpressionStarts) { bool SawError = false; - while (1) { + while (true) { if (ExpressionStarts) ExpressionStarts(); @@ -3418,7 +3418,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, bool Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs, SmallVectorImpl<SourceLocation> &CommaLocs) { - while (1) { + while (true) { ExprResult Expr = ParseAssignmentExpression(); if (Expr.isInvalid()) return true; diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 76c510ddd36c..2d38891c723f 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -668,7 +668,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false); Token Replacement; @@ -1877,8 +1877,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { QualType PreferredType; if (TypeRep) PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DS.getEndLoc(), Exprs, T.getOpenLocation()); + TypeRep.get()->getCanonicalTypeInternal(), DS.getEndLoc(), Exprs, + T.getOpenLocation(), /*Braced=*/false); CalledSignatureHelp = true; return PreferredType; }; @@ -1953,6 +1953,9 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context, /// \param Loc The location of the start of the statement that requires this /// condition, e.g., the "for" in a for loop. /// +/// \param MissingOK Whether an empty condition is acceptable here. Otherwise +/// it is considered an error to be recovered from. +/// /// \param FRI If non-null, a for range declaration is permitted, and if /// present will be parsed and stored here, and a null result will be returned. /// @@ -1960,11 +1963,10 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context, /// appropriate moment for a 'for' loop. /// /// \returns The parsed condition. -Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, - SourceLocation Loc, - Sema::ConditionKind CK, - ForRangeInfo *FRI, - bool EnterForConditionScope) { +Sema::ConditionResult +Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, + Sema::ConditionKind CK, bool MissingOK, + ForRangeInfo *FRI, bool EnterForConditionScope) { // Helper to ensure we always enter a continue/break scope if requested. struct ForConditionScopeRAII { Scope *S; @@ -2019,7 +2021,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, } ConsumeToken(); *InitStmt = Actions.ActOnNullStmt(SemiLoc); - return ParseCXXCondition(nullptr, Loc, CK); + return ParseCXXCondition(nullptr, Loc, CK, MissingOK); } // Parse the expression. @@ -2031,10 +2033,11 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, WarnOnInit(); *InitStmt = Actions.ActOnExprStmt(Expr.get()); ConsumeToken(); - return ParseCXXCondition(nullptr, Loc, CK); + return ParseCXXCondition(nullptr, Loc, CK, MissingOK); } - return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK); + return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK, + MissingOK); } case ConditionOrInitStatement::InitStmtDecl: { @@ -2048,7 +2051,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, DG = ParseSimpleDeclaration(DeclaratorContext::SelectionInit, DeclEnd, attrs, /*RequireSemi=*/true); *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd); - return ParseCXXCondition(nullptr, Loc, CK); + return ParseCXXCondition(nullptr, Loc, CK, MissingOK); } case ConditionOrInitStatement::ForRangeDecl: { @@ -2454,8 +2457,8 @@ bool Parser::ParseUnqualifiedIdTemplateId( // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs, - RAngleLoc)) + if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs, RAngleLoc, + Template)) return true; // If this is a non-template, we already issued a diagnostic. @@ -3167,8 +3170,9 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { // `new decltype(invalid) (^)`. if (TypeRep) PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); + TypeRep.get()->getCanonicalTypeInternal(), + DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen, + /*Braced=*/false); CalledSignatureHelp = true; return PreferredType; }; @@ -3585,7 +3589,7 @@ ExprResult Parser::ParseRequiresExpression() { // We need to consume the typename to allow 'requires { typename a; }' SourceLocation TypenameKWLoc = ConsumeToken(); - if (TryAnnotateCXXScopeToken()) { + if (TryAnnotateOptionalCXXScopeToken()) { TPA.Commit(); SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); break; diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index 9d9c03d28a97..fd0faba9c1c1 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -459,12 +459,22 @@ ExprResult Parser::ParseBraceInitializer() { Actions, EnterExpressionEvaluationContext::InitList); bool InitExprsOk = true; - DesignatorCompletionInfo DesignatorCompletion{ - InitExprs, - PreferredType.get(T.getOpenLocation()), + QualType LikelyType = PreferredType.get(T.getOpenLocation()); + DesignatorCompletionInfo DesignatorCompletion{InitExprs, LikelyType}; + bool CalledSignatureHelp = false; + auto RunSignatureHelp = [&] { + QualType PreferredType; + if (!LikelyType.isNull()) + PreferredType = Actions.ProduceConstructorSignatureHelp( + LikelyType->getCanonicalTypeInternal(), T.getOpenLocation(), + InitExprs, T.getOpenLocation(), /*Braced=*/true); + CalledSignatureHelp = true; + return PreferredType; }; - while (1) { + while (true) { + PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp); + // Handle Microsoft __if_exists/if_not_exists if necessary. if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 9e145f57d61f..f493ac9b92ca 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -134,7 +134,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { SmallVector<SourceLocation, 8> ClassLocs; SmallVector<ObjCTypeParamList *, 8> ClassTypeParams; - while (1) { + while (true) { MaybeSkipAttributes(tok::objc_class); if (expectIdentifier()) { SkipUntil(tok::semi); @@ -598,7 +598,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, SourceRange AtEnd; - while (1) { + while (true) { // If this is a method prototype, parse it. if (Tok.isOneOf(tok::minus, tok::plus)) { if (Decl *methodPrototype = @@ -848,7 +848,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - while (1) { + while (true) { if (Tok.is(tok::code_completion)) { cutOffParsing(); Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS); @@ -1149,7 +1149,7 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, assert(Context == DeclaratorContext::ObjCParameter || Context == DeclaratorContext::ObjCResult); - while (1) { + while (true) { if (Tok.is(tok::code_completion)) { cutOffParsing(); Actions.CodeCompleteObjCPassingType( @@ -1401,7 +1401,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Scope::FunctionDeclarationScope | Scope::DeclScope); AttributePool allParamAttrs(AttrFactory); - while (1) { + while (true) { ParsedAttributes paramAttrs(AttrFactory); Sema::ObjCArgInfo ArgInfo; @@ -1531,7 +1531,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, SmallVector<IdentifierLocPair, 8> ProtocolIdents; - while (1) { + while (true) { if (Tok.is(tok::code_completion)) { cutOffParsing(); Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents); @@ -2050,7 +2050,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc)); // Parse the list of forward declarations. - while (1) { + while (true) { ConsumeToken(); // the ',' if (expectIdentifier()) { SkipUntil(tok::semi); @@ -3179,7 +3179,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, ExprVector KeyExprs; if (Tok.is(tok::colon)) { - while (1) { + while (true) { // Each iteration parses a single keyword argument. KeyIdents.push_back(selIdent); KeyLocs.push_back(Loc); @@ -3599,7 +3599,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { unsigned nColons = 0; if (Tok.isNot(tok::r_paren)) { - while (1) { + while (true) { if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++. ++nColons; KeyIdents.push_back(nullptr); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 300b022d83b9..8ad5edb1bcd6 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/UniqueVector.h" +#include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPContext.h" using namespace clang; @@ -469,8 +470,8 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { SourceLocation LParLoc = T.getOpenLocation(); auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() { QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), - OmpPrivParm->getLocation(), Exprs, LParLoc); + OmpPrivParm->getType()->getCanonicalTypeInternal(), + OmpPrivParm->getLocation(), Exprs, LParLoc, /*Braced=*/false); CalledSignatureHelp = true; return PreferredType; }; @@ -1813,38 +1814,55 @@ parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) { void Parser::ParseOMPDeclareTargetClauses( Sema::DeclareTargetContextInfo &DTCI) { SourceLocation DeviceTypeLoc; - bool RequiresToOrLinkClause = false; - bool HasToOrLinkClause = false; + bool RequiresToOrLinkOrIndirectClause = false; + bool HasToOrLinkOrIndirectClause = false; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To; bool HasIdentifier = Tok.is(tok::identifier); if (HasIdentifier) { // If we see any clause we need a to or link clause. - RequiresToOrLinkClause = true; + RequiresToOrLinkOrIndirectClause = true; IdentifierInfo *II = Tok.getIdentifierInfo(); StringRef ClauseName = II->getName(); bool IsDeviceTypeClause = getLangOpts().OpenMP >= 50 && getOpenMPClauseKind(ClauseName) == OMPC_device_type; + bool IsIndirectClause = getLangOpts().OpenMP >= 51 && + getOpenMPClauseKind(ClauseName) == OMPC_indirect; + if (DTCI.Indirect.hasValue() && IsIndirectClause) { + Diag(Tok, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(OMPD_declare_target) + << getOpenMPClauseName(OMPC_indirect) << 0; + break; + } bool IsToOrLinkClause = OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT); assert((!IsDeviceTypeClause || !IsToOrLinkClause) && "Cannot be both!"); - if (!IsDeviceTypeClause && DTCI.Kind == OMPD_begin_declare_target) { + if (!IsDeviceTypeClause && !IsIndirectClause && + DTCI.Kind == OMPD_begin_declare_target) { Diag(Tok, diag::err_omp_declare_target_unexpected_clause) - << ClauseName << 0; + << ClauseName << (getLangOpts().OpenMP >= 51 ? 3 : 0); break; } - if (!IsDeviceTypeClause && !IsToOrLinkClause) { + if (!IsDeviceTypeClause && !IsToOrLinkClause && !IsIndirectClause) { Diag(Tok, diag::err_omp_declare_target_unexpected_clause) - << ClauseName << (getLangOpts().OpenMP >= 50 ? 2 : 1); + << ClauseName + << (getLangOpts().OpenMP >= 51 ? 4 + : getLangOpts().OpenMP >= 50 ? 2 + : 1); break; } - if (IsToOrLinkClause) - HasToOrLinkClause = true; + if (IsToOrLinkClause || IsIndirectClause) + HasToOrLinkOrIndirectClause = true; + if (IsIndirectClause) { + if (!ParseOpenMPIndirectClause(DTCI, /*ParseOnly*/ false)) + break; + continue; + } // Parse 'device_type' clause and go to next clause if any. if (IsDeviceTypeClause) { Optional<SimpleClauseData> DevTypeData = @@ -1910,10 +1928,14 @@ void Parser::ParseOMPDeclareTargetClauses( ConsumeToken(); } + if (DTCI.Indirect.hasValue() && DTCI.DT != OMPDeclareTargetDeclAttr::DT_Any) + Diag(DeviceTypeLoc, diag::err_omp_declare_target_indirect_device_type); + // For declare target require at least 'to' or 'link' to be present. - if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkClause && - !HasToOrLinkClause) - Diag(DTCI.Loc, diag::err_omp_declare_target_missing_to_or_link_clause); + if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkOrIndirectClause && + !HasToOrLinkOrIndirectClause) + Diag(DTCI.Loc, diag::err_omp_declare_target_missing_to_or_link_clause) + << (getLangOpts().OpenMP >= 51 ? 1 : 0); SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } @@ -2188,12 +2210,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( VariantMatchInfo VMI; TI.getAsVariantMatchInfo(ASTCtx, VMI); - std::function<void(StringRef)> DiagUnknownTrait = [this, Loc]( - StringRef ISATrait) { - // TODO Track the selector locations in a way that is accessible here to - // improve the diagnostic location. - Diag(Loc, diag::warn_unknown_begin_declare_variant_isa_trait) << ISATrait; - }; + std::function<void(StringRef)> DiagUnknownTrait = + [this, Loc](StringRef ISATrait) { + // TODO Track the selector locations in a way that is accessible here + // to improve the diagnostic location. + Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait; + }; TargetOMPContext OMPCtx( ASTCtx, std::move(DiagUnknownTrait), /* CurrentFunctionDecl */ nullptr, @@ -2282,11 +2304,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_declare_target: { SourceLocation DTLoc = ConsumeAnyToken(); bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end); - bool HasImplicitMappings = - DKind == OMPD_begin_declare_target || !HasClauses; Sema::DeclareTargetContextInfo DTCI(DKind, DTLoc); if (HasClauses) ParseOMPDeclareTargetClauses(DTCI); + bool HasImplicitMappings = + DKind == OMPD_begin_declare_target || !HasClauses || + (DTCI.ExplicitlyMapped.empty() && DTCI.Indirect.hasValue()); // Skip the last annot_pragma_openmp_end. ConsumeAnyToken(); @@ -2528,7 +2551,13 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { TPA.Revert(); // End of the first iteration. Parser is reset to the start of metadirective - TargetOMPContext OMPCtx(ASTContext, /* DiagUnknownTrait */ nullptr, + std::function<void(StringRef)> DiagUnknownTrait = + [this, Loc](StringRef ISATrait) { + // TODO Track the selector locations in a way that is accessible here + // to improve the diagnostic location. + Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait; + }; + TargetOMPContext OMPCtx(ASTContext, std::move(DiagUnknownTrait), /* CurrentFunctionDecl */ nullptr, ArrayRef<llvm::omp::TraitProperty>()); @@ -2936,7 +2965,7 @@ bool Parser::ParseOpenMPSimpleVarList( if (AllowScopeSpecifier && getLangOpts().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, false)) { + /*ObjectHasErrors=*/false, false)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -3383,6 +3412,47 @@ OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc); } +/// Parse indirect clause for '#pragma omp declare target' directive. +/// 'indirect' '[' '(' invoked-by-fptr ')' ']' +/// where invoked-by-fptr is a constant boolean expression that evaluates to +/// true or false at compile time. +bool Parser::ParseOpenMPIndirectClause(Sema::DeclareTargetContextInfo &DTCI, + bool ParseOnly) { + SourceLocation Loc = ConsumeToken(); + SourceLocation RLoc; + + if (Tok.isNot(tok::l_paren)) { + if (ParseOnly) + return false; + DTCI.Indirect = nullptr; + return true; + } + + ExprResult Val = + ParseOpenMPParensExpr(getOpenMPClauseName(OMPC_indirect), RLoc); + if (Val.isInvalid()) + return false; + + if (ParseOnly) + return false; + + if (!Val.get()->isValueDependent() && !Val.get()->isTypeDependent() && + !Val.get()->isInstantiationDependent() && + !Val.get()->containsUnexpandedParameterPack()) { + ExprResult Ret = Actions.CheckBooleanCondition(Loc, Val.get()); + if (Ret.isInvalid()) + return false; + llvm::APSInt Result; + Ret = Actions.VerifyIntegerConstantExpression(Val.get(), &Result, + Sema::AllowFold); + if (Ret.isInvalid()) + return false; + DTCI.Indirect = Val.get(); + return true; + } + return false; +} + /// Parsing of OpenMP clauses that use an interop-var. /// /// init-clause: @@ -3817,7 +3887,7 @@ bool Parser::parseMapperModifier(OpenMPVarListDataTy &Data) { if (getLangOpts().CPlusPlus) ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false); if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) { Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier); @@ -4050,7 +4120,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, if (getLangOpts().CPlusPlus) ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false); InvalidReductionId = ParseReductionId( *this, Data.ReductionOrMapperIdScopeSpec, UnqualifiedReductionId); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 292ab03e8614..ee07775b6346 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1068,7 +1068,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { SourceLocation LabelLoc = ConsumeToken(); SmallVector<Decl *, 8> DeclsInGroup; - while (1) { + while (true) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; break; @@ -1191,22 +1191,24 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, Sema::ConditionResult &Cond, SourceLocation Loc, - Sema::ConditionKind CK, + Sema::ConditionKind CK, bool MissingOK, SourceLocation *LParenLoc, SourceLocation *RParenLoc) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); + SourceLocation Start = Tok.getLocation(); - if (getLangOpts().CPlusPlus) - Cond = ParseCXXCondition(InitStmt, Loc, CK); - else { + if (getLangOpts().CPlusPlus) { + Cond = ParseCXXCondition(InitStmt, Loc, CK, MissingOK); + } else { ExprResult CondExpr = ParseExpression(); // If required, convert to a boolean value. if (CondExpr.isInvalid()) Cond = Sema::ConditionError(); else - Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK); + Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK, + MissingOK); } // If the parser was confused by the condition and we don't have a ')', try to @@ -1220,7 +1222,16 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, return true; } - // Otherwise the condition is valid or the rparen is present. + if (Cond.isInvalid()) { + ExprResult CondExpr = Actions.CreateRecoveryExpr( + Start, Tok.getLocation() == Start ? Start : PrevTokLocation, {}, + Actions.PreferredConditionType(CK)); + if (!CondExpr.isInvalid()) + Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK, + MissingOK); + } + + // Either the condition is valid or the rparen is present. T.consumeClose(); if (LParenLoc != nullptr) { @@ -1404,7 +1415,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc, IsConstexpr ? Sema::ConditionKind::ConstexprIf : Sema::ConditionKind::Boolean, - &LParen, &RParen)) + /*MissingOK=*/false, &LParen, &RParen)) return StmtError(); if (IsConstexpr) @@ -1599,7 +1610,8 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { SourceLocation LParen; SourceLocation RParen; if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc, - Sema::ConditionKind::Switch, &LParen, &RParen)) + Sema::ConditionKind::Switch, + /*MissingOK=*/false, &LParen, &RParen)) return StmtError(); StmtResult Switch = Actions.ActOnStartOfSwitchStmt( @@ -1689,7 +1701,8 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { SourceLocation LParen; SourceLocation RParen; if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc, - Sema::ConditionKind::Boolean, &LParen, &RParen)) + Sema::ConditionKind::Boolean, + /*MissingOK=*/false, &LParen, &RParen)) return StmtError(); // C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if @@ -1780,10 +1793,18 @@ StmtResult Parser::ParseDoStatement() { // A do-while expression is not a condition, so can't have attributes. DiagnoseAndSkipCXX11Attributes(); + SourceLocation Start = Tok.getLocation(); ExprResult Cond = ParseExpression(); // Correct the typos in condition before closing the scope. if (Cond.isUsable()) Cond = Actions.CorrectDelayedTyposInExpr(Cond); + else { + if (!Tok.isOneOf(tok::r_paren, tok::r_square, tok::r_brace)) + SkipUntil(tok::semi); + Cond = Actions.CreateRecoveryExpr( + Start, Start == Tok.getLocation() ? Start : PrevTokLocation, {}, + Actions.getASTContext().BoolTy); + } T.consumeClose(); DoScope.Exit(); @@ -2038,10 +2059,11 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // for-range-declaration next. bool MightBeForRangeStmt = !ForRangeInfo.ParsedForRangeDecl(); ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); - SecondPart = - ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean, - MightBeForRangeStmt ? &ForRangeInfo : nullptr, - /*EnterForConditionScope*/ true); + SecondPart = ParseCXXCondition( + nullptr, ForLoc, Sema::ConditionKind::Boolean, + // FIXME: recovery if we don't see another semi! + /*MissingOK=*/true, MightBeForRangeStmt ? &ForRangeInfo : nullptr, + /*EnterForConditionScope*/ true); if (ForRangeInfo.ParsedForRangeDecl()) { Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc() @@ -2065,9 +2087,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { if (SecondExpr.isInvalid()) SecondPart = Sema::ConditionError(); else - SecondPart = - Actions.ActOnCondition(getCurScope(), ForLoc, SecondExpr.get(), - Sema::ConditionKind::Boolean); + SecondPart = Actions.ActOnCondition( + getCurScope(), ForLoc, SecondExpr.get(), + Sema::ConditionKind::Boolean, /*MissingOK=*/true); } } } diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index 3e9ce8fd668f..04c3a8700c10 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -222,7 +222,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, CXXScopeSpec SS; if (getLangOpts().CPlusPlus) ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false); // Require an identifier here. @@ -508,7 +508,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { TokLoc = Tok.getLocation(); ++NumTokensRead; SkippedStartOfLine = false; - } while (1); + } while (true); if (BraceNesting && BraceCount != savedBraceCount) { // __asm without closing brace (this can happen at EOF). @@ -681,7 +681,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { /// asm-qualifier /// asm-qualifier-list asm-qualifier bool Parser::parseGNUAsmQualifierListOpt(GNUAsmQualifiers &AQ) { - while (1) { + while (true) { const GNUAsmQualifiers::AQ A = getGNUAsmQualifier(Tok); if (A == GNUAsmQualifiers::AQ_unspecified) { if (Tok.isNot(tok::l_paren)) { @@ -810,7 +810,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { } // Parse the asm-string list for clobbers if present. if (!AteExtraColon && isTokenStringLiteral()) { - while (1) { + while (true) { ExprResult Clobber(ParseAsmStringLiteral(/*ForAsmLabel*/ false)); if (Clobber.isInvalid()) @@ -888,7 +888,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) return false; - while (1) { + while (true) { // Read the [id] if present. if (Tok.is(tok::l_square)) { BalancedDelimiterTracker T(*this, tok::l_square); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 45af61a3926a..f875e3bf43e8 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -391,7 +391,7 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier( SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, /*EnteringContext=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false, /*MayBePseudoDestructor=*/nullptr, /*IsTypename=*/false, /*LastII=*/nullptr, /*OnlyNamespace=*/true) || SS.isInvalid()) { @@ -500,7 +500,7 @@ bool Parser::ParseTemplateParameters( bool Parser::ParseTemplateParameterList(const unsigned Depth, SmallVectorImpl<NamedDecl*> &TemplateParams) { - while (1) { + while (true) { if (NamedDecl *TmpParam = ParseTemplateParameter(Depth, TemplateParams.size())) { @@ -715,7 +715,7 @@ bool Parser::TryAnnotateTypeConstraint() { CXXScopeSpec SS; bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false, /*MayBePseudoDestructor=*/nullptr, // If this is not a type-constraint, then @@ -787,7 +787,7 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { bool TypenameKeyword = false; SourceLocation KeyLoc; ParseOptionalCXXScopeSpecifier(TypeConstraintSS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext*/ false); if (Tok.is(tok::annot_template_id)) { // Consume the 'type-constraint'. @@ -1222,7 +1222,6 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation LAngleLoc, return false; } - /// Parses a template-id that after the template name has /// already been parsed. /// @@ -1234,11 +1233,13 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation LAngleLoc, /// token that forms the template-id. Otherwise, we will leave the /// last token in the stream (e.g., so that it can be replaced with an /// annotation token). -bool -Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, - SourceLocation &LAngleLoc, - TemplateArgList &TemplateArgs, - SourceLocation &RAngleLoc) { +/// +/// \param NameHint is not required, and merely affects code completion. +bool Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, + SourceLocation &LAngleLoc, + TemplateArgList &TemplateArgs, + SourceLocation &RAngleLoc, + TemplateTy Template) { assert(Tok.is(tok::less) && "Must have already parsed the template-name"); // Consume the '<'. @@ -1251,7 +1252,7 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, if (!Tok.isOneOf(tok::greater, tok::greatergreater, tok::greatergreatergreater, tok::greaterequal, tok::greatergreaterequal)) - Invalid = ParseTemplateArgumentList(TemplateArgs); + Invalid = ParseTemplateArgumentList(TemplateArgs, Template, LAngleLoc); if (Invalid) { // Try to find the closing '>'. @@ -1332,8 +1333,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateArgList TemplateArgs; bool ArgsInvalid = false; if (!TypeConstraint || Tok.is(tok::less)) { - ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, - TemplateArgs, RAngleLoc); + ArgsInvalid = ParseTemplateIdAfterTemplateName( + false, LAngleLoc, TemplateArgs, RAngleLoc, Template); // If we couldn't recover from invalid arguments, don't form an annotation // token -- we don't know how much to annotate. // FIXME: This can lead to duplicate diagnostics if we retry parsing this @@ -1467,7 +1468,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { // '>', or (in some cases) '>>'. CXXScopeSpec SS; // nested-name-specifier, if present ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false); ParsedTemplateArgument Result; @@ -1585,19 +1586,34 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { /// template-argument-list: [C++ 14.2] /// template-argument /// template-argument-list ',' template-argument -bool -Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { +/// +/// \param Template is only used for code completion, and may be null. +bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs, + TemplateTy Template, + SourceLocation OpenLoc) { ColonProtectionRAIIObject ColonProtection(*this, false); + auto RunSignatureHelp = [&] { + if (!Template) + return QualType(); + CalledSignatureHelp = true; + return Actions.ProduceTemplateArgumentSignatureHelp(Template, TemplateArgs, + OpenLoc); + }; + do { + PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp); ParsedTemplateArgument Arg = ParseTemplateArgument(); SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc); - if (Arg.isInvalid()) + if (Arg.isInvalid()) { + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); return true; + } // Save this template argument. TemplateArgs.push_back(Arg); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 35c9036fb27e..512993a5278e 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -277,7 +277,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { /// '{' '}' /// Parser::TPResult Parser::TryParseInitDeclaratorList() { - while (1) { + while (true) { // declarator TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/); if (TPR != TPResult::Ambiguous) @@ -1068,7 +1068,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, if (mayHaveDirectInit) return TPResult::Ambiguous; - while (1) { + while (true) { TPResult TPR(TPResult::Ambiguous); if (Tok.is(tok::l_paren)) { @@ -1898,7 +1898,7 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, // parameter-declaration // parameter-declaration-list ',' parameter-declaration // - while (1) { + while (true) { // '...'[opt] if (Tok.is(tok::ellipsis)) { ConsumeToken(); diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 11113fa1a060..ffa1e0f027f1 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -279,7 +279,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { // We always want this function to skip at least one token if the first token // isn't T and if not at EOF. bool isFirstTokenSkipped = true; - while (1) { + while (true) { // If we found one of the tokens, stop and return true. for (unsigned i = 0, NumToks = Toks.size(); i != NumToks; ++i) { if (Tok.is(Toks[i])) { @@ -1448,7 +1448,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { ParseDeclarator(ParmDeclarator); // Handle the full declarator list. - while (1) { + while (true) { // If attributes are present, parse them. MaybeParseGNUAttributes(ParmDeclarator); @@ -1634,7 +1634,7 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { CXXScopeSpec SS; if (getLangOpts().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, EnteringContext)) return ANK_Error; @@ -1882,7 +1882,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false, nullptr, /*IsTypename*/ true)) return true; @@ -1953,7 +1953,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { CXXScopeSpec SS; if (getLangOpts().CPlusPlus) if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext*/ false)) return true; @@ -2084,7 +2084,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, EnteringContext)) return true; if (SS.isEmpty()) @@ -2195,7 +2195,7 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { // Parse nested-name-specifier. if (getLangOpts().CPlusPlus) ParseOptionalCXXScopeSpecifier(Result.SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false); // Check nested-name specifier. diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp index e9b678b69594..70ea2fcd3d04 100644 --- a/clang/lib/Rewrite/HTMLRewrite.cpp +++ b/clang/lib/Rewrite/HTMLRewrite.cpp @@ -542,7 +542,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { // Lex all the tokens in raw mode, to avoid entering #includes or expanding // macros. - while (1) { + while (true) { Token Tok; L.LexFromRawLexer(Tok); diff --git a/clang/lib/Rewrite/Rewriter.cpp b/clang/lib/Rewrite/Rewriter.cpp index 3b06afc76e16..8950bfb7c4dc 100644 --- a/clang/lib/Rewrite/Rewriter.cpp +++ b/clang/lib/Rewrite/Rewriter.cpp @@ -223,6 +223,7 @@ std::string Rewriter::getRewrittenText(CharSourceRange Range) const { RewriteBuffer::iterator Start = RB.begin(); std::advance(Start, StartOff); RewriteBuffer::iterator End = Start; + assert(EndOff >= StartOff && "Invalid iteration distance"); std::advance(End, EndOff-StartOff); return std::string(Start, End); diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index b4dcc9759b99..ac5ad52c0b1d 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -128,7 +128,7 @@ class LogicalErrorHandler : public CFGCallback { Sema &S; public: - LogicalErrorHandler(Sema &S) : CFGCallback(), S(S) {} + LogicalErrorHandler(Sema &S) : S(S) {} static bool HasMacroID(const Expr *E) { if (E->getExprLoc().isMacroID()) diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index 0a2ca54e244a..fefe20941f17 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -506,11 +506,92 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { case CK_FunctionType: return Type; + + case CK_Template: + case CK_Aggregate: + return nullptr; } llvm_unreachable("Invalid CandidateKind!"); } +unsigned CodeCompleteConsumer::OverloadCandidate::getNumParams() const { + if (Kind == CK_Template) + return Template->getTemplateParameters()->size(); + + if (Kind == CK_Aggregate) { + unsigned Count = + std::distance(AggregateType->field_begin(), AggregateType->field_end()); + if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) + Count += CRD->getNumBases(); + return Count; + } + + if (const auto *FT = getFunctionType()) + if (const auto *FPT = dyn_cast<FunctionProtoType>(FT)) + return FPT->getNumParams(); + + return 0; +} + +QualType +CodeCompleteConsumer::OverloadCandidate::getParamType(unsigned N) const { + if (Kind == CK_Aggregate) { + if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) { + if (N < CRD->getNumBases()) + return std::next(CRD->bases_begin(), N)->getType(); + N -= CRD->getNumBases(); + } + for (const auto *Field : AggregateType->fields()) + if (N-- == 0) + return Field->getType(); + return QualType(); + } + + if (Kind == CK_Template) { + TemplateParameterList *TPL = getTemplate()->getTemplateParameters(); + if (N < TPL->size()) + if (const auto *D = dyn_cast<NonTypeTemplateParmDecl>(TPL->getParam(N))) + return D->getType(); + return QualType(); + } + + if (const auto *FT = getFunctionType()) + if (const auto *FPT = dyn_cast<FunctionProtoType>(FT)) + if (N < FPT->getNumParams()) + return FPT->getParamType(N); + return QualType(); +} + +const NamedDecl * +CodeCompleteConsumer::OverloadCandidate::getParamDecl(unsigned N) const { + if (Kind == CK_Aggregate) { + if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) { + if (N < CRD->getNumBases()) + return std::next(CRD->bases_begin(), N)->getType()->getAsTagDecl(); + N -= CRD->getNumBases(); + } + for (const auto *Field : AggregateType->fields()) + if (N-- == 0) + return Field; + return nullptr; + } + + if (Kind == CK_Template) { + TemplateParameterList *TPL = getTemplate()->getTemplateParameters(); + if (N < TPL->size()) + return TPL->getParam(N); + return nullptr; + } + + // Note that if we only have a FunctionProtoType, we don't have param decls. + if (const auto *FD = getFunction()) { + if (N < FD->param_size()) + return FD->getParamDecl(N); + } + return nullptr; +} + //===----------------------------------------------------------------------===// // Code completion consumer implementation //===----------------------------------------------------------------------===// @@ -645,7 +726,7 @@ static std::string getOverloadAsString(const CodeCompletionString &CCS) { void PrintingCodeCompleteConsumer::ProcessOverloadCandidates( Sema &SemaRef, unsigned CurrentArg, OverloadCandidate *Candidates, - unsigned NumCandidates, SourceLocation OpenParLoc) { + unsigned NumCandidates, SourceLocation OpenParLoc, bool Braced) { OS << "OPENING_PAREN_LOC: "; OpenParLoc.print(OS, SemaRef.getSourceManager()); OS << "\n"; @@ -653,7 +734,7 @@ void PrintingCodeCompleteConsumer::ProcessOverloadCandidates( for (unsigned I = 0; I != NumCandidates; ++I) { if (CodeCompletionString *CCS = Candidates[I].CreateSignatureString( CurrentArg, SemaRef, getAllocator(), CCTUInfo, - includeBriefComments())) { + includeBriefComments(), Braced)) { OS << "OVERLOAD: " << getOverloadAsString(*CCS) << "\n"; } } diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td index 38debc5aa9fc..df2f206041c1 100644 --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -80,11 +80,14 @@ def FuncExtKhrLocalInt32ExtendedAtomics : FunctionExtension<"cl_khr_local_int32 def FuncExtKhrInt64BaseAtomics : FunctionExtension<"cl_khr_int64_base_atomics">; def FuncExtKhrInt64ExtendedAtomics : FunctionExtension<"cl_khr_int64_extended_atomics">; def FuncExtKhrMipmapImage : FunctionExtension<"cl_khr_mipmap_image">; +def FuncExtKhrMipmapImageReadWrite : FunctionExtension<"cl_khr_mipmap_image __opencl_c_read_write_images">; def FuncExtKhrMipmapImageWrites : FunctionExtension<"cl_khr_mipmap_image_writes">; def FuncExtKhrGlMsaaSharing : FunctionExtension<"cl_khr_gl_msaa_sharing">; +def FuncExtKhrGlMsaaSharingReadWrite : FunctionExtension<"cl_khr_gl_msaa_sharing __opencl_c_read_write_images">; def FuncExtOpenCLCPipes : FunctionExtension<"__opencl_c_pipes">; def FuncExtOpenCLCWGCollectiveFunctions : FunctionExtension<"__opencl_c_work_group_collective_functions">; +def FuncExtOpenCLCReadWriteImages : FunctionExtension<"__opencl_c_read_write_images">; def FuncExtFloatAtomicsFp16GlobalLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store">; def FuncExtFloatAtomicsFp16LocalLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_load_store">; def FuncExtFloatAtomicsFp16GenericLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store __opencl_c_ext_fp16_local_atomic_load_store">; @@ -1390,30 +1393,35 @@ foreach coordTy = [Int, Float] in { } // --- Table 23: Sampler-less Read Functions --- +multiclass ImageReadSamplerless<string aQual> { + foreach imgTy = [Image2d, Image1dArray] in { + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; + } + foreach imgTy = [Image3d, Image2dArray] in { + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; + } + foreach imgTy = [Image1d, Image1dBuffer] in { + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; + } + def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>], Attr.Pure>; + def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>], Attr.Pure>; +} + let MinVersion = CL12 in { - foreach aQual = ["RO", "RW"] in { - foreach imgTy = [Image2d, Image1dArray] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; - } - foreach imgTy = [Image3d, Image2dArray] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; - } - foreach imgTy = [Image1d, Image1dBuffer] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; - } - def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>], Attr.Pure>; - def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>], Attr.Pure>; + defm : ImageReadSamplerless<"RO">; + let Extension = FuncExtOpenCLCReadWriteImages in { + defm : ImageReadSamplerless<"RW">; } } // --- Table 24: Image Write Functions --- -foreach aQual = ["WO", "RW"] in { +multiclass ImageWrite<string aQual> { foreach imgTy = [Image2d] in { def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>; def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>; @@ -1443,8 +1451,13 @@ foreach aQual = ["WO", "RW"] in { def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Float]>; } +defm : ImageWrite<"WO">; +let Extension = FuncExtOpenCLCReadWriteImages in { + defm : ImageWrite<"RW">; +} + // --- Table 25: Image Query Functions --- -foreach aQual = ["RO", "WO", "RW"] in { +multiclass ImageQuery<string aQual> { foreach imgTy = [Image1d, Image1dBuffer, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in { @@ -1468,6 +1481,12 @@ foreach aQual = ["RO", "WO", "RW"] in { } } +defm : ImageQuery<"RO">; +defm : ImageQuery<"WO">; +let Extension = FuncExtOpenCLCReadWriteImages in { + defm : ImageQuery<"RW">; +} + // OpenCL extension v2.0 s5.1.9: Built-in Image Read Functions // --- Table 8 --- foreach aQual = ["RO"] in { @@ -1488,7 +1507,7 @@ foreach aQual = ["RO"] in { // OpenCL extension v2.0 s5.1.10: Built-in Image Sampler-less Read Functions // --- Table 9 --- let MinVersion = CL12 in { - foreach aQual = ["RO", "RW"] in { + multiclass ImageReadHalf<string aQual> { foreach name = ["read_imageh"] in { foreach imgTy = [Image2d, Image1dArray] in { def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; @@ -1501,10 +1520,14 @@ let MinVersion = CL12 in { } } } + defm : ImageReadHalf<"RO">; + let Extension = FuncExtOpenCLCReadWriteImages in { + defm : ImageReadHalf<"RW">; + } } // OpenCL extension v2.0 s5.1.11: Built-in Image Write Functions // --- Table 10 --- -foreach aQual = ["WO", "RW"] in { +multiclass ImageWriteHalf<string aQual> { foreach name = ["write_imageh"] in { def : Builtin<name, [Void, ImageType<Image2d, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>; def : Builtin<name, [Void, ImageType<Image2dArray, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>; @@ -1515,6 +1538,12 @@ foreach aQual = ["WO", "RW"] in { } } +defm : ImageWriteHalf<"WO">; +let Extension = FuncExtOpenCLCReadWriteImages in { + defm : ImageWriteHalf<"RW">; +} + + //-------------------------------------------------------------------- // OpenCL v2.0 s6.13.15 - Work-group Functions @@ -1688,14 +1717,24 @@ let Extension = FuncExtKhrMipmapImage in { } } } - // Added to section 6.13.14.5 - foreach aQual = ["RO", "WO", "RW"] in { - foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in { - def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>; - } +} + +// Added to section 6.13.14.5 +multiclass ImageQueryNumMipLevels<string aQual> { + foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in { + def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>; } } +let Extension = FuncExtKhrMipmapImage in { + defm : ImageQueryNumMipLevels<"RO">; + defm : ImageQueryNumMipLevels<"WO">; +} + +let Extension = FuncExtKhrMipmapImageReadWrite in { + defm : ImageQueryNumMipLevels<"RW">; +} + // Write functions are enabled using a separate extension. let Extension = FuncExtKhrMipmapImageWrites in { // Added to section 6.13.14.4. @@ -1734,41 +1773,50 @@ let Extension = FuncExtKhrMipmapImageWrites in { //-------------------------------------------------------------------- // OpenCL Extension v2.0 s18.3 - Creating OpenCL Memory Objects from OpenGL MSAA Textures -let Extension = FuncExtKhrGlMsaaSharing in { - // --- Table 6.13.14.3 --- - foreach aQual = ["RO", "RW"] in { - foreach imgTy = [Image2dMsaa] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; - } - foreach imgTy = [Image2dArrayMsaa] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; - } - foreach name = ["read_imagef"] in { - def : Builtin<name, [Float, ImageType<Image2dMsaaDepth, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; - def : Builtin<name, [Float, ImageType<Image2dArrayMsaaDepth, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; - } +// --- Table 6.13.14.3 --- +multiclass ImageReadMsaa<string aQual> { + foreach imgTy = [Image2dMsaa] in { + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; + } + foreach imgTy = [Image2dArrayMsaa] in { + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; + } + foreach name = ["read_imagef"] in { + def : Builtin<name, [Float, ImageType<Image2dMsaaDepth, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; + def : Builtin<name, [Float, ImageType<Image2dArrayMsaaDepth, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; } +} - // --- Table 6.13.14.5 --- - foreach aQual = ["RO", "WO", "RW"] in { - foreach imgTy = [Image2dMsaa, Image2dArrayMsaa, Image2dMsaaDepth, Image2dArrayMsaaDepth] in { - foreach name = ["get_image_width", "get_image_height", - "get_image_channel_data_type", "get_image_channel_order", - "get_image_num_samples"] in { - def : Builtin<name, [Int, ImageType<imgTy, aQual>], Attr.Const>; - } - def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>], Attr.Const>; - } - foreach imgTy = [Image2dArrayMsaa, Image2dArrayMsaaDepth] in { - def : Builtin<"get_image_array_size", [Size, ImageType<imgTy, aQual>], Attr.Const>; +// --- Table 6.13.14.5 --- +multiclass ImageQueryMsaa<string aQual> { + foreach imgTy = [Image2dMsaa, Image2dArrayMsaa, Image2dMsaaDepth, Image2dArrayMsaaDepth] in { + foreach name = ["get_image_width", "get_image_height", + "get_image_channel_data_type", "get_image_channel_order", + "get_image_num_samples"] in { + def : Builtin<name, [Int, ImageType<imgTy, aQual>], Attr.Const>; } + def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>], Attr.Const>; + } + foreach imgTy = [Image2dArrayMsaa, Image2dArrayMsaaDepth] in { + def : Builtin<"get_image_array_size", [Size, ImageType<imgTy, aQual>], Attr.Const>; } } +let Extension = FuncExtKhrGlMsaaSharing in { + defm : ImageReadMsaa<"RO">; + defm : ImageQueryMsaa<"RO">; + defm : ImageQueryMsaa<"WO">; +} + +let Extension = FuncExtKhrGlMsaaSharingReadWrite in { + defm : ImageReadMsaa<"RW">; + defm : ImageQueryMsaa<"RW">; +} + //-------------------------------------------------------------------- // OpenCL Extension v2.0 s28 - Subgroups // --- Table 28.2.1 --- diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp index 51b0b24e57b7..499279a2659d 100644 --- a/clang/lib/Sema/Scope.cpp +++ b/clang/lib/Sema/Scope.cpp @@ -91,7 +91,7 @@ void Scope::Init(Scope *parent, unsigned flags) { UsingDirectives.clear(); Entity = nullptr; ErrorTrap.reset(); - NRVO.setPointerAndInt(nullptr, 0); + NRVO.setPointerAndInt(nullptr, false); } bool Scope::containedInPrototypeScope() const { diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 734ed0f62ec6..20b4a9a5d4e6 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -60,6 +60,16 @@ ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); } DarwinSDKInfo * Sema::getDarwinSDKInfoForAvailabilityChecking(SourceLocation Loc, StringRef Platform) { + auto *SDKInfo = getDarwinSDKInfoForAvailabilityChecking(); + if (!SDKInfo && !WarnedDarwinSDKInfoMissing) { + Diag(Loc, diag::warn_missing_sdksettings_for_availability_checking) + << Platform; + WarnedDarwinSDKInfoMissing = true; + } + return SDKInfo; +} + +DarwinSDKInfo *Sema::getDarwinSDKInfoForAvailabilityChecking() { if (CachedDarwinSDKInfo) return CachedDarwinSDKInfo->get(); auto SDKInfo = parseDarwinSDKInfo( @@ -71,8 +81,6 @@ Sema::getDarwinSDKInfoForAvailabilityChecking(SourceLocation Loc, } if (!SDKInfo) llvm::consumeError(SDKInfo.takeError()); - Diag(Loc, diag::warn_missing_sdksettings_for_availability_checking) - << Platform; CachedDarwinSDKInfo = std::unique_ptr<DarwinSDKInfo>(); return nullptr; } @@ -187,7 +195,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, CodeSegStack(nullptr), FpPragmaStack(FPOptionsOverride()), CurInitSeg(nullptr), VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr), - IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr), + IsBuildingRecoveryCallExpr(false), LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr), StdCoroutineTraitsCache(nullptr), CXXTypeInfoDecl(nullptr), @@ -324,9 +332,12 @@ void Sema::Initialize() { Context.getTargetInfo().getSupportedOpenCLOpts(), getLangOpts()); addImplicitTypedef("sampler_t", Context.OCLSamplerTy); addImplicitTypedef("event_t", Context.OCLEventTy); - if (getLangOpts().getOpenCLCompatibleVersion() >= 200) { - addImplicitTypedef("clk_event_t", Context.OCLClkEventTy); - addImplicitTypedef("queue_t", Context.OCLQueueTy); + auto OCLCompatibleVersion = getLangOpts().getOpenCLCompatibleVersion(); + if (OCLCompatibleVersion >= 200) { + if (getLangOpts().OpenCLCPlusPlus || getLangOpts().Blocks) { + addImplicitTypedef("clk_event_t", Context.OCLClkEventTy); + addImplicitTypedef("queue_t", Context.OCLQueueTy); + } if (getLangOpts().OpenCLPipes) addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy); addImplicitTypedef("atomic_int", Context.getAtomicType(Context.IntTy)); @@ -394,7 +405,6 @@ void Sema::Initialize() { } } - #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ if (getOpenCLOptions().isSupported(#Ext, getLangOpts())) { \ addImplicitTypedef(#ExtType, Context.Id##Ty); \ @@ -1858,6 +1868,15 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { if (isUnevaluatedContext() || Ty.isNull()) return; + // The original idea behind checkTypeSupport function is that unused + // declarations can be replaced with an array of bytes of the same size during + // codegen, such replacement doesn't seem to be possible for types without + // constant byte size like zero length arrays. So, do a deep check for SYCL. + if (D && LangOpts.SYCLIsDevice) { + llvm::DenseSet<QualType> Visited; + deepTypeCheckForSYCLDevice(Loc, Visited, D); + } + Decl *C = cast<Decl>(getCurLexicalContext()); // Memcpy operations for structs containing a member with unsupported type @@ -1932,7 +1951,8 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { }; auto CheckType = [&](QualType Ty, bool IsRetTy = false) { - if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) + if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) || + LangOpts.CUDAIsDevice) CheckDeviceType(Ty); QualType UnqualTy = Ty.getCanonicalType().getUnqualifiedType(); @@ -2534,6 +2554,11 @@ static bool IsCPUDispatchCPUSpecificMultiVersion(const Expr *E) { bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain, bool (*IsPlausibleResult)(QualType)) { + if (isSFINAEContext()) { + // If this is a SFINAE context, don't try anything that might trigger ADL + // prematurely. + return false; + } SourceLocation Loc = E.get()->getExprLoc(); SourceRange Range = E.get()->getSourceRange(); diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 8cecf6c6ab4f..4781d71080c9 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -881,7 +881,8 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T); - DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc()); + DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc()); + DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd()); SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), ColonColonLoc); return false; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 4e83fa1fffca..c8fb36b8311a 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -499,7 +499,8 @@ public: 1 /* null byte always written by sprintf */) {} bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, - const char *, unsigned SpecifierLen) override { + const char *, unsigned SpecifierLen, + const TargetInfo &) override { const size_t FieldWidth = computeFieldWidth(FS); const size_t Precision = computePrecision(FS); @@ -1578,11 +1579,26 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) { return TheCall; } +// Emit an error and return true if the current object format type is in the +// list of unsupported types. +static bool CheckBuiltinTargetNotInUnsupported( + Sema &S, unsigned BuiltinID, CallExpr *TheCall, + ArrayRef<llvm::Triple::ObjectFormatType> UnsupportedObjectFormatTypes) { + llvm::Triple::ObjectFormatType CurObjFormat = + S.getASTContext().getTargetInfo().getTriple().getObjectFormat(); + if (llvm::is_contained(UnsupportedObjectFormatTypes, CurObjFormat)) { + S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) + << TheCall->getSourceRange(); + return true; + } + return false; +} + // Emit an error and return true if the current architecture is not in the list // of supported architectures. static bool -CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall, - ArrayRef<llvm::Triple::ArchType> SupportedArchs) { +CheckBuiltinTargetInSupported(Sema &S, unsigned BuiltinID, CallExpr *TheCall, + ArrayRef<llvm::Triple::ArchType> SupportedArchs) { llvm::Triple::ArchType CurArch = S.getASTContext().getTargetInfo().getTriple().getArch(); if (llvm::is_contained(SupportedArchs, CurArch)) @@ -1664,6 +1680,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, switch (BuiltinID) { case Builtin::BI__builtin___CFStringMakeConstantString: + // CFStringMakeConstantString is currently not implemented for GOFF (i.e., + // on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported + if (CheckBuiltinTargetNotInUnsupported( + *this, BuiltinID, TheCall, + {llvm::Triple::GOFF, llvm::Triple::XCOFF})) + return ExprError(); assert(TheCall->getNumArgs() == 1 && "Wrong # arguments to builtin CFStringMakeConstantString"); if (CheckObjCString(TheCall->getArg(0))) @@ -1698,7 +1720,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI_interlockedbittestandreset_acq: case Builtin::BI_interlockedbittestandreset_rel: case Builtin::BI_interlockedbittestandreset_nf: - if (CheckBuiltinTargetSupport( + if (CheckBuiltinTargetInSupported( *this, BuiltinID, TheCall, {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64})) return ExprError(); @@ -1711,9 +1733,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI_bittestandset64: case Builtin::BI_interlockedbittestandreset64: case Builtin::BI_interlockedbittestandset64: - if (CheckBuiltinTargetSupport(*this, BuiltinID, TheCall, - {llvm::Triple::x86_64, llvm::Triple::arm, - llvm::Triple::thumb, llvm::Triple::aarch64})) + if (CheckBuiltinTargetInSupported(*this, BuiltinID, TheCall, + {llvm::Triple::x86_64, llvm::Triple::arm, + llvm::Triple::thumb, + llvm::Triple::aarch64})) return ExprError(); break; @@ -1750,10 +1773,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case Builtin::BI__builtin_alloca_with_align: + case Builtin::BI__builtin_alloca_with_align_uninitialized: if (SemaBuiltinAllocaWithAlign(TheCall)) return ExprError(); LLVM_FALLTHROUGH; case Builtin::BI__builtin_alloca: + case Builtin::BI__builtin_alloca_uninitialized: Diag(TheCall->getBeginLoc(), diag::warn_alloca) << TheCall->getDirectCallee(); break; @@ -2189,9 +2214,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } - // __builtin_elementwise_ceil restricts the element type to floating point + // These builtins restrict the element type to floating point // types only. - case Builtin::BI__builtin_elementwise_ceil: { + case Builtin::BI__builtin_elementwise_ceil: + case Builtin::BI__builtin_elementwise_floor: + case Builtin::BI__builtin_elementwise_roundeven: + case Builtin::BI__builtin_elementwise_trunc: { if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) return ExprError(); @@ -2232,8 +2260,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } - // __builtin_reduce_xor supports vector of integers only. - case Builtin::BI__builtin_reduce_xor: { + // These builtins support vectors of integers only. + case Builtin::BI__builtin_reduce_xor: + case Builtin::BI__builtin_reduce_or: + case Builtin::BI__builtin_reduce_and: { if (PrepareBuiltinReduceMathOneArgCall(TheCall)) return ExprError(); @@ -3946,23 +3976,39 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, // Check if each required feature is included for (StringRef F : ReqFeatures) { - if (TI.hasFeature(F)) - continue; - - // If the feature is 64bit, alter the string so it will print better in - // the diagnostic. - if (F == "64bit") - F = "RV64"; + SmallVector<StringRef> ReqOpFeatures; + F.split(ReqOpFeatures, '|'); + bool HasFeature = false; + for (StringRef OF : ReqOpFeatures) { + if (TI.hasFeature(OF)) { + HasFeature = true; + continue; + } + } - // Convert features like "zbr" and "experimental-zbr" to "Zbr". - F.consume_front("experimental-"); - std::string FeatureStr = F.str(); - FeatureStr[0] = std::toupper(FeatureStr[0]); + if (!HasFeature) { + std::string FeatureStrs = ""; + for (StringRef OF : ReqOpFeatures) { + // If the feature is 64bit, alter the string so it will print better in + // the diagnostic. + if (OF == "64bit") + OF = "RV64"; - // Error message - FeatureMissing = true; - Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension) - << TheCall->getSourceRange() << StringRef(FeatureStr); + // Convert features like "zbr" and "experimental-zbr" to "Zbr". + OF.consume_front("experimental-"); + std::string FeatureStr = OF.str(); + FeatureStr[0] = std::toupper(FeatureStr[0]); + // Combine strings. + FeatureStrs += FeatureStrs == "" ? "" : ", "; + FeatureStrs += "'"; + FeatureStrs += FeatureStr; + FeatureStrs += "'"; + } + // Error message + FeatureMissing = true; + Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension) + << TheCall->getSourceRange() << StringRef(FeatureStrs); + } } if (FeatureMissing) @@ -8880,8 +8926,8 @@ public: void handleInvalidMaskType(StringRef MaskType) override; bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, - const char *startSpecifier, - unsigned specifierLen) override; + const char *startSpecifier, unsigned specifierLen, + const TargetInfo &Target) override; bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, unsigned SpecifierLen, @@ -9140,11 +9186,9 @@ bool CheckPrintfHandler::checkForCStrMembers( return false; } -bool -CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier - &FS, - const char *startSpecifier, - unsigned specifierLen) { +bool CheckPrintfHandler::HandlePrintfSpecifier( + const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, + unsigned specifierLen, const TargetInfo &Target) { using namespace analyze_format_string; using namespace analyze_printf; @@ -9276,6 +9320,15 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier } } + const llvm::Triple &Triple = Target.getTriple(); + if (CS.getKind() == ConversionSpecifier::nArg && + (Triple.isAndroid() || Triple.isOSFuchsia())) { + EmitFormatDiagnostic(S.PDiag(diag::warn_printf_narg_not_supported), + getLocationOfByte(CS.getStart()), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + } + // Check for invalid use of field width if (!FS.hasValidFieldWidth()) { HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0, @@ -14021,7 +14074,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> { const Expr *UsageExpr; SequenceTree::Seq Seq; - Usage() : UsageExpr(nullptr), Seq() {} + Usage() : UsageExpr(nullptr) {} }; struct UsageInfo { @@ -14030,7 +14083,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> { /// Have we issued a diagnostic for this object already? bool Diagnosed; - UsageInfo() : Uses(), Diagnosed(false) {} + UsageInfo() : Diagnosed(false) {} }; using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>; diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 93c07ccc891f..01fdf51c60c3 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -36,6 +36,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" @@ -98,7 +99,7 @@ private: unsigned SingleDeclIndex; public: - ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) {} + ShadowMapEntry() : SingleDeclIndex(0) {} ShadowMapEntry(const ShadowMapEntry &) = delete; ShadowMapEntry(ShadowMapEntry &&Move) { *this = std::move(Move); } ShadowMapEntry &operator=(const ShadowMapEntry &) = delete; @@ -1437,7 +1438,7 @@ bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const { bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const { if (!IsOrdinaryNonTypeName(ND)) - return 0; + return false; if (const auto *VD = dyn_cast<ValueDecl>(ND->getUnderlyingDecl())) if (VD->getType()->isIntegralOrEnumerationType()) @@ -1895,6 +1896,7 @@ static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context, Policy.SuppressStrongLifetime = true; Policy.SuppressUnwrittenScope = true; Policy.SuppressScope = true; + Policy.CleanUglifiedParameters = true; return Policy; } @@ -2816,14 +2818,18 @@ formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, Optional<ArrayRef<QualType>> ObjCSubsts = None); static std::string -FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, - bool SuppressName = false, bool SuppressBlock = false, +FormatFunctionParameter(const PrintingPolicy &Policy, + const DeclaratorDecl *Param, bool SuppressName = false, + bool SuppressBlock = false, Optional<ArrayRef<QualType>> ObjCSubsts = None) { // Params are unavailable in FunctionTypeLoc if the FunctionType is invalid. // It would be better to pass in the param Type, which is usually available. // But this case is rare, so just pretend we fell back to int as elsewhere. if (!Param) return "int"; + Decl::ObjCDeclQualifier ObjCQual = Decl::OBJC_TQ_None; + if (const auto *PVD = dyn_cast<ParmVarDecl>(Param)) + ObjCQual = PVD->getObjCDeclQualifier(); bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { @@ -2832,18 +2838,17 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, std::string Result; if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName) - Result = std::string(Param->getIdentifier()->getName()); + Result = std::string(Param->getIdentifier()->deuglifiedName()); QualType Type = Param->getType(); if (ObjCSubsts) Type = Type.substObjCTypeArgs(Param->getASTContext(), *ObjCSubsts, ObjCSubstitutionContext::Parameter); if (ObjCMethodParam) { - Result = - "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type); + Result = "(" + formatObjCParamQualifiers(ObjCQual, Type); Result += Type.getAsString(Policy) + ")"; if (Param->getIdentifier() && !SuppressName) - Result += Param->getIdentifier()->getName(); + Result += Param->getIdentifier()->deuglifiedName(); } else { Type.getAsStringInternal(Result, Policy); } @@ -2871,20 +2876,19 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, // for the block; just use the parameter type as a placeholder. std::string Result; if (!ObjCMethodParam && Param->getIdentifier()) - Result = std::string(Param->getIdentifier()->getName()); + Result = std::string(Param->getIdentifier()->deuglifiedName()); QualType Type = Param->getType().getUnqualifiedType(); if (ObjCMethodParam) { Result = Type.getAsString(Policy); - std::string Quals = - formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type); + std::string Quals = formatObjCParamQualifiers(ObjCQual, Type); if (!Quals.empty()) Result = "(" + Quals + " " + Result + ")"; if (Result.back() != ')') Result += " "; if (Param->getIdentifier()) - Result += Param->getIdentifier()->getName(); + Result += Param->getIdentifier()->deuglifiedName(); } else { Type.getAsStringInternal(Result, Policy); } @@ -3079,14 +3083,14 @@ static void AddTemplateParameterChunks( if (TTP->getIdentifier()) { PlaceholderStr += ' '; - PlaceholderStr += TTP->getIdentifier()->getName(); + PlaceholderStr += TTP->getIdentifier()->deuglifiedName(); } HasDefaultArg = TTP->hasDefaultArgument(); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { if (NTTP->getIdentifier()) - PlaceholderStr = std::string(NTTP->getIdentifier()->getName()); + PlaceholderStr = std::string(NTTP->getIdentifier()->deuglifiedName()); NTTP->getType().getAsStringInternal(PlaceholderStr, Policy); HasDefaultArg = NTTP->hasDefaultArgument(); } else { @@ -3098,7 +3102,7 @@ static void AddTemplateParameterChunks( PlaceholderStr = "template<...> class"; if (TTP->getIdentifier()) { PlaceholderStr += ' '; - PlaceholderStr += TTP->getIdentifier()->getName(); + PlaceholderStr += TTP->getIdentifier()->deuglifiedName(); } HasDefaultArg = TTP->hasDefaultArgument(); @@ -3688,6 +3692,31 @@ const RawComment *clang::getParameterComment( return nullptr; } +static void AddOverloadAggregateChunks(const RecordDecl *RD, + const PrintingPolicy &Policy, + CodeCompletionBuilder &Result, + unsigned CurrentArg) { + unsigned ChunkIndex = 0; + auto AddChunk = [&](llvm::StringRef Placeholder) { + if (ChunkIndex > 0) + Result.AddChunk(CodeCompletionString::CK_Comma); + const char *Copy = Result.getAllocator().CopyString(Placeholder); + if (ChunkIndex == CurrentArg) + Result.AddCurrentParameterChunk(Copy); + else + Result.AddPlaceholderChunk(Copy); + ++ChunkIndex; + }; + // Aggregate initialization has all bases followed by all fields. + // (Bases are not legal in C++11 but in that case we never get here). + if (auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) { + for (const auto &Base : CRD->bases()) + AddChunk(Base.getType().getAsString(Policy)); + } + for (const auto &Field : RD->fields()) + AddChunk(FormatFunctionParameter(Policy, Field)); +} + /// Add function overload parameter chunks to the given code completion /// string. static void AddOverloadParameterChunks(ASTContext &Context, @@ -3697,6 +3726,11 @@ static void AddOverloadParameterChunks(ASTContext &Context, CodeCompletionBuilder &Result, unsigned CurrentArg, unsigned Start = 0, bool InOptional = false) { + if (!Function && !Prototype) { + Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "..."); + return; + } + bool FirstParameter = true; unsigned NumParams = Function ? Function->getNumParams() : Prototype->getNumParams(); @@ -3757,10 +3791,83 @@ static void AddOverloadParameterChunks(ASTContext &Context, } } +static std::string +formatTemplateParameterPlaceholder(const NamedDecl *Param, bool &Optional, + const PrintingPolicy &Policy) { + if (const auto *Type = dyn_cast<TemplateTypeParmDecl>(Param)) { + Optional = Type->hasDefaultArgument(); + } else if (const auto *NonType = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + Optional = NonType->hasDefaultArgument(); + } else if (const auto *Template = dyn_cast<TemplateTemplateParmDecl>(Param)) { + Optional = Template->hasDefaultArgument(); + } + std::string Result; + llvm::raw_string_ostream OS(Result); + Param->print(OS, Policy); + return Result; +} + +static std::string templateResultType(const TemplateDecl *TD, + const PrintingPolicy &Policy) { + if (const auto *CTD = dyn_cast<ClassTemplateDecl>(TD)) + return CTD->getTemplatedDecl()->getKindName().str(); + if (const auto *VTD = dyn_cast<VarTemplateDecl>(TD)) + return VTD->getTemplatedDecl()->getType().getAsString(Policy); + if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(TD)) + return FTD->getTemplatedDecl()->getReturnType().getAsString(Policy); + if (isa<TypeAliasTemplateDecl>(TD)) + return "type"; + if (isa<TemplateTemplateParmDecl>(TD)) + return "class"; + if (isa<ConceptDecl>(TD)) + return "concept"; + return ""; +} + +static CodeCompletionString *createTemplateSignatureString( + const TemplateDecl *TD, CodeCompletionBuilder &Builder, unsigned CurrentArg, + const PrintingPolicy &Policy) { + llvm::ArrayRef<NamedDecl *> Params = TD->getTemplateParameters()->asArray(); + CodeCompletionBuilder OptionalBuilder(Builder.getAllocator(), + Builder.getCodeCompletionTUInfo()); + std::string ResultType = templateResultType(TD, Policy); + if (!ResultType.empty()) + Builder.AddResultTypeChunk(Builder.getAllocator().CopyString(ResultType)); + Builder.AddTextChunk( + Builder.getAllocator().CopyString(TD->getNameAsString())); + Builder.AddChunk(CodeCompletionString::CK_LeftAngle); + // Initially we're writing into the main string. Once we see an optional arg + // (with default), we're writing into the nested optional chunk. + CodeCompletionBuilder *Current = &Builder; + for (unsigned I = 0; I < Params.size(); ++I) { + bool Optional = false; + std::string Placeholder = + formatTemplateParameterPlaceholder(Params[I], Optional, Policy); + if (Optional) + Current = &OptionalBuilder; + if (I > 0) + Current->AddChunk(CodeCompletionString::CK_Comma); + Current->AddChunk(I == CurrentArg + ? CodeCompletionString::CK_CurrentParameter + : CodeCompletionString::CK_Placeholder, + Current->getAllocator().CopyString(Placeholder)); + } + // Add the optional chunk to the main string if we ever used it. + if (Current == &OptionalBuilder) + Builder.AddOptionalChunk(OptionalBuilder.TakeString()); + Builder.AddChunk(CodeCompletionString::CK_RightAngle); + // For function templates, ResultType was the function's return type. + // Give some clue this is a function. (Don't show the possibly-bulky params). + if (isa<FunctionTemplateDecl>(TD)) + Builder.AddInformativeChunk("()"); + return Builder.TakeString(); +} + CodeCompletionString * CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator, - CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) const { + CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments, + bool Braced) const { PrintingPolicy Policy = getCompletionPrintingPolicy(S); // Show signatures of constructors as they are declared: // vector(int n) rather than vector<string>(int n) @@ -3770,22 +3877,20 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( // FIXME: Set priority, availability appropriately. CodeCompletionBuilder Result(Allocator, CCTUInfo, 1, CXAvailability_Available); + + if (getKind() == CK_Template) + return createTemplateSignatureString(getTemplate(), Result, CurrentArg, + Policy); + FunctionDecl *FDecl = getFunction(); const FunctionProtoType *Proto = - dyn_cast<FunctionProtoType>(getFunctionType()); - if (!FDecl && !Proto) { - // Function without a prototype. Just give the return type and a - // highlighted ellipsis. - const FunctionType *FT = getFunctionType(); - Result.AddResultTypeChunk(Result.getAllocator().CopyString( - FT->getReturnType().getAsString(Policy))); - Result.AddChunk(CodeCompletionString::CK_LeftParen); - Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "..."); - Result.AddChunk(CodeCompletionString::CK_RightParen); - return Result.TakeString(); - } + dyn_cast_or_null<FunctionProtoType>(getFunctionType()); - if (FDecl) { + // First, the name/type of the callee. + if (getKind() == CK_Aggregate) { + Result.AddTextChunk( + Result.getAllocator().CopyString(getAggregate()->getName())); + } else if (FDecl) { if (IncludeBriefComments) { if (auto RC = getParameterComment(S.getASTContext(), *this, CurrentArg)) Result.addBriefComment(RC->getBriefText(S.getASTContext())); @@ -3797,14 +3902,21 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( FDecl->getDeclName().print(OS, Policy); Result.AddTextChunk(Result.getAllocator().CopyString(OS.str())); } else { + // Function without a declaration. Just give the return type. Result.AddResultTypeChunk(Result.getAllocator().CopyString( - Proto->getReturnType().getAsString(Policy))); + getFunctionType()->getReturnType().getAsString(Policy))); } - Result.AddChunk(CodeCompletionString::CK_LeftParen); - AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, Result, - CurrentArg); - Result.AddChunk(CodeCompletionString::CK_RightParen); + // Next, the brackets and parameters. + Result.AddChunk(Braced ? CodeCompletionString::CK_LeftBrace + : CodeCompletionString::CK_LeftParen); + if (getKind() == CK_Aggregate) + AddOverloadAggregateChunks(getAggregate(), Policy, Result, CurrentArg); + else + AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, Result, + CurrentArg); + Result.AddChunk(Braced ? CodeCompletionString::CK_RightBrace + : CodeCompletionString::CK_RightParen); return Result.TakeString(); } @@ -5408,11 +5520,18 @@ QualType getApproximateType(const Expr *E) { : getApproximateType(CDSME->getBase()); if (CDSME->isArrow() && !Base.isNull()) Base = Base->getPointeeType(); // could handle unique_ptr etc here? - RecordDecl *RD = Base.isNull() ? nullptr : getAsRecordDecl(Base); + auto *RD = + Base.isNull() + ? nullptr + : llvm::dyn_cast_or_null<CXXRecordDecl>(getAsRecordDecl(Base)); if (RD && RD->isCompleteDefinition()) { - for (const auto *Member : RD->lookup(CDSME->getMember())) - if (const ValueDecl *VD = llvm::dyn_cast<ValueDecl>(Member)) - return VD->getType().getNonReferenceType(); + // Look up member heuristically, including in bases. + for (const auto *Member : RD->lookupDependentName( + CDSME->getMember(), [](const NamedDecl *Member) { + return llvm::isa<ValueDecl>(Member); + })) { + return llvm::cast<ValueDecl>(Member)->getType().getNonReferenceType(); + } } } return Unresolved; @@ -5843,36 +5962,37 @@ static QualType getParamType(Sema &SemaRef, // overload candidates. QualType ParamType; for (auto &Candidate : Candidates) { - if (const auto *FType = Candidate.getFunctionType()) - if (const auto *Proto = dyn_cast<FunctionProtoType>(FType)) - if (N < Proto->getNumParams()) { - if (ParamType.isNull()) - ParamType = Proto->getParamType(N); - else if (!SemaRef.Context.hasSameUnqualifiedType( - ParamType.getNonReferenceType(), - Proto->getParamType(N).getNonReferenceType())) - // Otherwise return a default-constructed QualType. - return QualType(); - } + QualType CandidateParamType = Candidate.getParamType(N); + if (CandidateParamType.isNull()) + continue; + if (ParamType.isNull()) { + ParamType = CandidateParamType; + continue; + } + if (!SemaRef.Context.hasSameUnqualifiedType( + ParamType.getNonReferenceType(), + CandidateParamType.getNonReferenceType())) + // Two conflicting types, give up. + return QualType(); } return ParamType; } static QualType -ProduceSignatureHelp(Sema &SemaRef, Scope *S, - MutableArrayRef<ResultCandidate> Candidates, - unsigned CurrentArg, SourceLocation OpenParLoc) { +ProduceSignatureHelp(Sema &SemaRef, MutableArrayRef<ResultCandidate> Candidates, + unsigned CurrentArg, SourceLocation OpenParLoc, + bool Braced) { if (Candidates.empty()) return QualType(); if (SemaRef.getPreprocessor().isCodeCompletionReached()) SemaRef.CodeCompleter->ProcessOverloadCandidates( - SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc); + SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc, + Braced); return getParamType(SemaRef, Candidates, CurrentArg); } -QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn, - ArrayRef<Expr *> Args, +QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args, SourceLocation OpenParLoc) { Fn = unwrapParenList(Fn); if (!CodeCompleter || !Fn) @@ -5969,53 +6089,158 @@ QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn, } } mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size()); - QualType ParamType = - ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); + QualType ParamType = ProduceSignatureHelp(*this, Results, Args.size(), + OpenParLoc, /*Braced=*/false); return !CandidateSet.empty() ? ParamType : QualType(); } -QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type, +// Determine which param to continue aggregate initialization from after +// a designated initializer. +// +// Given struct S { int a,b,c,d,e; }: +// after `S{.b=1,` we want to suggest c to continue +// after `S{.b=1, 2,` we continue with d (this is legal C and ext in C++) +// after `S{.b=1, .a=2,` we continue with b (this is legal C and ext in C++) +// +// Possible outcomes: +// - we saw a designator for a field, and continue from the returned index. +// Only aggregate initialization is allowed. +// - we saw a designator, but it was complex or we couldn't find the field. +// Only aggregate initialization is possible, but we can't assist with it. +// Returns an out-of-range index. +// - we saw no designators, just positional arguments. +// Returns None. +static llvm::Optional<unsigned> +getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate, + ArrayRef<Expr *> Args) { + static constexpr unsigned Invalid = std::numeric_limits<unsigned>::max(); + assert(Aggregate.getKind() == ResultCandidate::CK_Aggregate); + + // Look for designated initializers. + // They're in their syntactic form, not yet resolved to fields. + IdentifierInfo *DesignatedFieldName = nullptr; + unsigned ArgsAfterDesignator = 0; + for (const Expr *Arg : Args) { + if (const auto *DIE = dyn_cast<DesignatedInitExpr>(Arg)) { + if (DIE->size() == 1 && DIE->getDesignator(0)->isFieldDesignator()) { + DesignatedFieldName = DIE->getDesignator(0)->getFieldName(); + ArgsAfterDesignator = 0; + } else { + return Invalid; // Complicated designator. + } + } else if (isa<DesignatedInitUpdateExpr>(Arg)) { + return Invalid; // Unsupported. + } else { + ++ArgsAfterDesignator; + } + } + if (!DesignatedFieldName) + return llvm::None; + + // Find the index within the class's fields. + // (Probing getParamDecl() directly would be quadratic in number of fields). + unsigned DesignatedIndex = 0; + const FieldDecl *DesignatedField = nullptr; + for (const auto *Field : Aggregate.getAggregate()->fields()) { + if (Field->getIdentifier() == DesignatedFieldName) { + DesignatedField = Field; + break; + } + ++DesignatedIndex; + } + if (!DesignatedField) + return Invalid; // Designator referred to a missing field, give up. + + // Find the index within the aggregate (which may have leading bases). + unsigned AggregateSize = Aggregate.getNumParams(); + while (DesignatedIndex < AggregateSize && + Aggregate.getParamDecl(DesignatedIndex) != DesignatedField) + ++DesignatedIndex; + + // Continue from the index after the last named field. + return DesignatedIndex + ArgsAfterDesignator + 1; +} + +QualType Sema::ProduceConstructorSignatureHelp(QualType Type, SourceLocation Loc, ArrayRef<Expr *> Args, - SourceLocation OpenParLoc) { + SourceLocation OpenParLoc, + bool Braced) { if (!CodeCompleter) return QualType(); + SmallVector<ResultCandidate, 8> Results; // A complete type is needed to lookup for constructors. - CXXRecordDecl *RD = - isCompleteType(Loc, Type) ? Type->getAsCXXRecordDecl() : nullptr; + RecordDecl *RD = + isCompleteType(Loc, Type) ? Type->getAsRecordDecl() : nullptr; if (!RD) return Type; + CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD); + + // Consider aggregate initialization. + // We don't check that types so far are correct. + // We also don't handle C99/C++17 brace-elision, we assume init-list elements + // are 1:1 with fields. + // FIXME: it would be nice to support "unwrapping" aggregates that contain + // a single subaggregate, like std::array<T, N> -> T __elements[N]. + if (Braced && !RD->isUnion() && + (!LangOpts.CPlusPlus || (CRD && CRD->isAggregate()))) { + ResultCandidate AggregateSig(RD); + unsigned AggregateSize = AggregateSig.getNumParams(); + + if (auto NextIndex = + getNextAggregateIndexAfterDesignatedInit(AggregateSig, Args)) { + // A designator was used, only aggregate init is possible. + if (*NextIndex >= AggregateSize) + return Type; + Results.push_back(AggregateSig); + return ProduceSignatureHelp(*this, Results, *NextIndex, OpenParLoc, + Braced); + } + + // Describe aggregate initialization, but also constructors below. + if (Args.size() < AggregateSize) + Results.push_back(AggregateSig); + } // FIXME: Provide support for member initializers. // FIXME: Provide support for variadic template constructors. - OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); + if (CRD) { + OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); + for (NamedDecl *C : LookupConstructors(CRD)) { + if (auto *FD = dyn_cast<FunctionDecl>(C)) { + // FIXME: we can't yet provide correct signature help for initializer + // list constructors, so skip them entirely. + if (Braced && LangOpts.CPlusPlus && isInitListConstructor(FD)) + continue; + AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args, + CandidateSet, + /*SuppressUserConversions=*/false, + /*PartialOverloading=*/true, + /*AllowExplicit*/ true); + } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) { + if (Braced && LangOpts.CPlusPlus && + isInitListConstructor(FTD->getTemplatedDecl())) + continue; - for (NamedDecl *C : LookupConstructors(RD)) { - if (auto *FD = dyn_cast<FunctionDecl>(C)) { - AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args, - CandidateSet, - /*SuppressUserConversions=*/false, - /*PartialOverloading=*/true, - /*AllowExplicit*/ true); - } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) { - AddTemplateOverloadCandidate( - FTD, DeclAccessPair::make(FTD, C->getAccess()), - /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet, - /*SuppressUserConversions=*/false, - /*PartialOverloading=*/true); + AddTemplateOverloadCandidate( + FTD, DeclAccessPair::make(FTD, C->getAccess()), + /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet, + /*SuppressUserConversions=*/false, + /*PartialOverloading=*/true); + } } + mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size()); } - SmallVector<ResultCandidate, 8> Results; - mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size()); - return ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); + return ProduceSignatureHelp(*this, Results, Args.size(), OpenParLoc, Braced); } QualType Sema::ProduceCtorInitMemberSignatureHelp( - Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, - ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc) { + Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, + ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc, + bool Braced) { if (!CodeCompleter) return QualType(); @@ -6026,12 +6251,66 @@ QualType Sema::ProduceCtorInitMemberSignatureHelp( // FIXME: Add support for Base class constructors as well. if (ValueDecl *MemberDecl = tryLookupCtorInitMemberDecl( Constructor->getParent(), SS, TemplateTypeTy, II)) - return ProduceConstructorSignatureHelp(getCurScope(), MemberDecl->getType(), + return ProduceConstructorSignatureHelp(MemberDecl->getType(), MemberDecl->getLocation(), ArgExprs, - OpenParLoc); + OpenParLoc, Braced); return QualType(); } +static bool argMatchesTemplateParams(const ParsedTemplateArgument &Arg, + unsigned Index, + const TemplateParameterList &Params) { + const NamedDecl *Param; + if (Index < Params.size()) + Param = Params.getParam(Index); + else if (Params.hasParameterPack()) + Param = Params.asArray().back(); + else + return false; // too many args + + switch (Arg.getKind()) { + case ParsedTemplateArgument::Type: + return llvm::isa<TemplateTypeParmDecl>(Param); // constraints not checked + case ParsedTemplateArgument::NonType: + return llvm::isa<NonTypeTemplateParmDecl>(Param); // type not checked + case ParsedTemplateArgument::Template: + return llvm::isa<TemplateTemplateParmDecl>(Param); // signature not checked + } + llvm_unreachable("Unhandled switch case"); +} + +QualType Sema::ProduceTemplateArgumentSignatureHelp( + TemplateTy ParsedTemplate, ArrayRef<ParsedTemplateArgument> Args, + SourceLocation LAngleLoc) { + if (!CodeCompleter || !ParsedTemplate) + return QualType(); + + SmallVector<ResultCandidate, 8> Results; + auto Consider = [&](const TemplateDecl *TD) { + // Only add if the existing args are compatible with the template. + bool Matches = true; + for (unsigned I = 0; I < Args.size(); ++I) { + if (!argMatchesTemplateParams(Args[I], I, *TD->getTemplateParameters())) { + Matches = false; + break; + } + } + if (Matches) + Results.emplace_back(TD); + }; + + TemplateName Template = ParsedTemplate.get(); + if (const auto *TD = Template.getAsTemplateDecl()) { + Consider(TD); + } else if (const auto *OTS = Template.getAsOverloadedTemplate()) { + for (const NamedDecl *ND : *OTS) + if (const auto *TD = llvm::dyn_cast<TemplateDecl>(ND)) + Consider(TD); + } + return ProduceSignatureHelp(*this, Results, Args.size(), LAngleLoc, + /*Braced=*/false); +} + static QualType getDesignatedType(QualType BaseType, const Designation &Desig) { for (unsigned I = 0; I < Desig.getNumDesignators(); ++I) { if (BaseType.isNull()) @@ -6073,7 +6352,15 @@ void Sema::CodeCompleteDesignator(QualType BaseType, CodeCompleter->getCodeCompletionTUInfo(), CCC); Results.EnterNewScope(); - for (const auto *FD : RD->fields()) { + for (const Decl *D : RD->decls()) { + const FieldDecl *FD; + if (auto *IFD = dyn_cast<IndirectFieldDecl>(D)) + FD = IFD->getAnonField(); + else if (auto *DFD = dyn_cast<FieldDecl>(D)) + FD = DFD; + else + continue; + // FIXME: Make use of previous designators to mark any fields before those // inaccessible, and also compute the next initializer priority. ResultBuilder::Result Result(FD, Results.getBasePriority(FD)); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 466e37831f66..ce99d4848cca 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -18,7 +18,6 @@ #include "clang/Sema/Template.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Initialization.h" -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/OperatorPrecedence.h" @@ -1058,7 +1057,7 @@ concepts::ExprRequirement::ExprRequirement( concepts::ExprRequirement::ReturnTypeRequirement:: ReturnTypeRequirement(TemplateParameterList *TPL) : - TypeConstraintInfo(TPL, 0) { + TypeConstraintInfo(TPL, false) { assert(TPL->size() == 1); const TypeConstraint *TC = cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint(); @@ -1070,7 +1069,7 @@ ReturnTypeRequirement(TemplateParameterList *TPL) : Constraint->getTemplateArgsAsWritten() && TemplateSpecializationType::anyInstantiationDependentTemplateArguments( Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1)); - TypeConstraintInfo.setInt(Dependent ? 1 : 0); + TypeConstraintInfo.setInt(Dependent ? true : false); } concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) : diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index e89cecd08cca..e7e60b7e7daf 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -653,7 +653,7 @@ static void checkNoThrow(Sema &S, const Stmt *E, } if (ThrowingDecls.empty()) { // [dcl.fct.def.coroutine]p15 - // The expression co_Âawait promise.final_Âsuspend() shall not be + // The expression co_await promise.final_suspend() shall not be // potentially-throwing ([except.spec]). // // First time seeing an error, emit the error message. @@ -663,32 +663,32 @@ static void checkNoThrow(Sema &S, const Stmt *E, ThrowingDecls.insert(D); } }; - auto SC = E->getStmtClass(); - if (SC == Expr::CXXConstructExprClass) { - auto const *Ctor = cast<CXXConstructExpr>(E)->getConstructor(); + + if (auto *CE = dyn_cast<CXXConstructExpr>(E)) { + CXXConstructorDecl *Ctor = CE->getConstructor(); checkDeclNoexcept(Ctor); // Check the corresponding destructor of the constructor. - checkDeclNoexcept(Ctor->getParent()->getDestructor(), true); - } else if (SC == Expr::CallExprClass || SC == Expr::CXXMemberCallExprClass || - SC == Expr::CXXOperatorCallExprClass) { - if (!cast<CallExpr>(E)->isTypeDependent()) { - checkDeclNoexcept(cast<CallExpr>(E)->getCalleeDecl()); - auto ReturnType = cast<CallExpr>(E)->getCallReturnType(S.getASTContext()); - // Check the destructor of the call return type, if any. - if (ReturnType.isDestructedType() == - QualType::DestructionKind::DK_cxx_destructor) { - const auto *T = - cast<RecordType>(ReturnType.getCanonicalType().getTypePtr()); - checkDeclNoexcept( - dyn_cast<CXXRecordDecl>(T->getDecl())->getDestructor(), true); - } + checkDeclNoexcept(Ctor->getParent()->getDestructor(), /*IsDtor=*/true); + } else if (auto *CE = dyn_cast<CallExpr>(E)) { + if (CE->isTypeDependent()) + return; + + checkDeclNoexcept(CE->getCalleeDecl()); + QualType ReturnType = CE->getCallReturnType(S.getASTContext()); + // Check the destructor of the call return type, if any. + if (ReturnType.isDestructedType() == + QualType::DestructionKind::DK_cxx_destructor) { + const auto *T = + cast<RecordType>(ReturnType.getCanonicalType().getTypePtr()); + checkDeclNoexcept(dyn_cast<CXXRecordDecl>(T->getDecl())->getDestructor(), + /*IsDtor=*/true); + } + } else + for (const auto *Child : E->children()) { + if (!Child) + continue; + checkNoThrow(S, Child, ThrowingDecls); } - } - for (const auto *Child : E->children()) { - if (!Child) - continue; - checkNoThrow(S, Child, ThrowingDecls); - } } bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) { @@ -1184,13 +1184,13 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() { "cannot make statement while the promise type is dependent"); // [dcl.fct.def.coroutine]p10 - // If a search for the name get_Âreturn_Âobject_Âon_Âallocation_Âfailure in + // If a search for the name get_return_object_on_allocation_failure in // the scope of the promise type ([class.member.lookup]) finds any // declarations, then the result of a call to an allocation function used to // obtain storage for the coroutine state is assumed to return nullptr if it // fails to obtain storage, ... If the allocation function returns nullptr, // ... and the return value is obtained by a call to - // T::get_Âreturn_Âobject_Âon_Âallocation_Âfailure(), where T is the + // T::get_return_object_on_allocation_failure(), where T is the // promise type. DeclarationName DN = S.PP.getIdentifierInfo("get_return_object_on_allocation_failure"); @@ -1433,10 +1433,10 @@ bool CoroutineStmtBuilder::makeOnFallthrough() { "cannot make statement while the promise type is dependent"); // [dcl.fct.def.coroutine]/p6 - // If searches for the names return_Âvoid and return_Âvalue in the scope of + // If searches for the names return_void and return_value in the scope of // the promise type each find any declarations, the program is ill-formed. - // [Note 1: If return_Âvoid is found, flowing off the end of a coroutine is - // equivalent to a co_Âreturn with no operand. Otherwise, flowing off the end + // [Note 1: If return_void is found, flowing off the end of a coroutine is + // equivalent to a co_return with no operand. Otherwise, flowing off the end // of a coroutine results in undefined behavior ([stmt.return.coroutine]). — // end note] bool HasRVoid, HasRValue; @@ -1529,7 +1529,7 @@ bool CoroutineStmtBuilder::makeOnException() { bool CoroutineStmtBuilder::makeReturnObject() { // [dcl.fct.def.coroutine]p7 - // The expression promise.get_Âreturn_Âobject() is used to initialize the + // The expression promise.get_return_object() is used to initialize the // returned reference or prvalue result object of a call to a coroutine. ExprResult ReturnObject = buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None); @@ -1740,30 +1740,39 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc, return nullptr; } - if (!InStd) { - // Found only in std::experimental. - Diag(KwLoc, diag::warn_deprecated_coroutine_namespace) - << "coroutine_traits"; - } else if (InExp) { - // Found in std and std::experimental. - Diag(KwLoc, - diag::err_mixed_use_std_and_experimental_namespace_for_coroutine); - Diag(KwLoc, diag::warn_deprecated_coroutine_namespace) - << "coroutine_traits"; - return nullptr; - } - // Prefer ::std to std::experimental. auto &Result = InStd ? ResStd : ResExp; CoroTraitsNamespaceCache = InStd ? StdSpace : ExpSpace; // coroutine_traits is required to be a class template. - if (!(StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>())) { + StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>(); + if (!StdCoroutineTraitsCache) { Result.suppressDiagnostics(); NamedDecl *Found = *Result.begin(); Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); return nullptr; } + + if (InExp) { + // Found in std::experimental + Diag(KwLoc, diag::warn_deprecated_coroutine_namespace) + << "coroutine_traits"; + ResExp.suppressDiagnostics(); + auto *Found = *ResExp.begin(); + Diag(Found->getLocation(), diag::note_entity_declared_at) << Found; + + if (InStd && + StdCoroutineTraitsCache != ResExp.getAsSingle<ClassTemplateDecl>()) { + // Also found something different in std + Diag(KwLoc, + diag::err_mixed_use_std_and_experimental_namespace_for_coroutine); + Diag(StdCoroutineTraitsCache->getLocation(), + diag::note_entity_declared_at) + << StdCoroutineTraitsCache; + + return nullptr; + } + } } Namespace = CoroTraitsNamespaceCache; return StdCoroutineTraitsCache; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 3c58f1d19c04..3252671991b7 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1586,10 +1586,13 @@ void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, /// We've determined that \p New is a redeclaration of \p Old. Check that they /// have compatible owning modules. bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { - // FIXME: The Modules TS is not clear about how friend declarations are - // to be treated. It's not meaningful to have different owning modules for - // linkage in redeclarations of the same entity, so for now allow the - // redeclaration and change the owning modules to match. + // [module.interface]p7: + // A declaration is attached to a module as follows: + // - If the declaration is a non-dependent friend declaration that nominates a + // function with a declarator-id that is a qualified-id or template-id or that + // nominates a class other than with an elaborated-type-specifier with neither + // a nested-name-specifier nor a simple-template-id, it is attached to the + // module to which the friend is attached ([basic.link]). if (New->getFriendObjectKind() && Old->getOwningModuleForLinkage() != New->getOwningModuleForLinkage()) { New->setLocalOwningModule(Old->getOwningModule()); @@ -1628,6 +1631,52 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { return false; } +// [module.interface]p6: +// A redeclaration of an entity X is implicitly exported if X was introduced by +// an exported declaration; otherwise it shall not be exported. +bool Sema::CheckRedeclarationExported(NamedDecl *New, NamedDecl *Old) { + // [module.interface]p1: + // An export-declaration shall inhabit a namespace scope. + // + // So it is meaningless to talk about redeclaration which is not at namespace + // scope. + if (!New->getLexicalDeclContext() + ->getNonTransparentContext() + ->isFileContext() || + !Old->getLexicalDeclContext() + ->getNonTransparentContext() + ->isFileContext()) + return false; + + bool IsNewExported = New->isInExportDeclContext(); + bool IsOldExported = Old->isInExportDeclContext(); + + // It should be irrevelant if both of them are not exported. + if (!IsNewExported && !IsOldExported) + return false; + + if (IsOldExported) + return false; + + assert(IsNewExported); + + Diag(New->getLocation(), diag::err_redeclaration_non_exported) << New; + Diag(Old->getLocation(), diag::note_previous_declaration); + return true; +} + +// A wrapper function for checking the semantic restrictions of +// a redeclaration within a module. +bool Sema::CheckRedeclarationInModule(NamedDecl *New, NamedDecl *Old) { + if (CheckRedeclarationModuleOwnership(New, Old)) + return true; + + if (CheckRedeclarationExported(New, Old)) + return true; + + return false; +} + static bool isUsingDecl(NamedDecl *D) { return isa<UsingShadowDecl>(D) || isa<UnresolvedUsingTypenameDecl>(D) || @@ -3390,7 +3439,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, } } - if (CheckRedeclarationModuleOwnership(New, Old)) + if (CheckRedeclarationInModule(New, Old)) return true; if (!getLangOpts().CPlusPlus) { @@ -4269,7 +4318,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } - if (CheckRedeclarationModuleOwnership(New, Old)) + if (CheckRedeclarationInModule(New, Old)) return; // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. @@ -5759,7 +5808,15 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, else if (isa<BlockDecl>(Cur)) Diag(Loc, diag::err_invalid_declarator_in_block) << Name << SS.getRange(); - else + else if (isa<ExportDecl>(Cur)) { + if (!isa<NamespaceDecl>(DC)) + Diag(Loc, diag::err_export_non_namespace_scope_name) + << Name << SS.getRange(); + else + // The cases that DC is not NamespaceDecl should be handled in + // CheckRedeclarationExported. + return false; + } else Diag(Loc, diag::err_invalid_declarator_scope) << Name << cast<NamedDecl>(Cur) << cast<NamedDecl>(DC) << SS.getRange(); @@ -7798,8 +7855,6 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, DeclarationName Name = R.getLookupName(); // Emit warning and note. - if (getSourceManager().isInSystemMacro(R.getNameLoc())) - return; ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC); Diag(R.getNameLoc(), WarningDiag) << Name << Kind << OldDC; if (!CaptureLoc.isInvalid()) @@ -9128,6 +9183,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_in_union); NewFD->setInvalidDecl(); } + if ((Parent->isClass() || Parent->isStruct()) && + Parent->hasAttr<SYCLSpecialClassAttr>() && + NewFD->getKind() == Decl::Kind::CXXMethod && + NewFD->getName() == "__init" && D.isFunctionDefinition()) { + if (auto *Def = Parent->getDefinition()) + Def->setInitMethod(true); + } } SetNestedNameSpecifier(*this, NewFD, D); @@ -9921,7 +9983,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << NewFD; // Turn this into a variadic function with no parameters. - const FunctionType *FT = NewFD->getType()->getAs<FunctionType>(); + const auto *FT = NewFD->getType()->castAs<FunctionType>(); FunctionProtoType::ExtProtoInfo EPI( Context.getDefaultCallingConvention(true, false)); EPI.Variadic = true; @@ -14632,8 +14694,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, Diag(FD->getLocation(), diag::ext_pure_function_definition); if (!FD->isInvalidDecl()) { - // Don't diagnose unused parameters of defaulted or deleted functions. - if (!FD->isDeleted() && !FD->isDefaulted() && !FD->hasSkippedBody()) + // Don't diagnose unused parameters of defaulted, deleted or naked + // functions. + if (!FD->isDeleted() && !FD->isDefaulted() && !FD->hasSkippedBody() && + !FD->hasAttr<NakedAttr>()) DiagnoseUnusedParameters(FD->parameters()); DiagnoseSizeOfParametersAndReturnValue(FD->parameters(), FD->getReturnType(), FD); @@ -15002,7 +15066,24 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, diag_id = diag::ext_implicit_function_decl; else diag_id = diag::warn_implicit_function_decl; + + TypoCorrection Corrected; + // Because typo correction is expensive, only do it if the implicit + // function declaration is going to be treated as an error. + // + // Perform the corection before issuing the main diagnostic, as some consumers + // use typo-correction callbacks to enhance the main diagnostic. + if (S && !ExternCPrev && + (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error)) { + DeclFilterCCC<FunctionDecl> CCC{}; + Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc), LookupOrdinaryName, + S, nullptr, CCC, CTK_NonError); + } + Diag(Loc, diag_id) << &II; + if (Corrected) + diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion), + /*ErrorRecovery*/ false); // If we found a prior declaration of this function, don't bother building // another one. We've already pushed that one into scope, so there's nothing @@ -15010,18 +15091,6 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, if (ExternCPrev) return ExternCPrev; - // Because typo correction is expensive, only do it if the implicit - // function declaration is going to be treated as an error. - if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) { - TypoCorrection Corrected; - DeclFilterCCC<FunctionDecl> CCC{}; - if (S && (Corrected = - CorrectTypo(DeclarationNameInfo(&II, Loc), LookupOrdinaryName, - S, nullptr, CCC, CTK_NonError))) - diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion), - /*ErrorRecovery*/false); - } - // Set a Declarator for the implicit definition: int foo(); const char *Dummy; AttributeFactory attrFactory; @@ -15191,11 +15260,11 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); - // We make "fma" on some platforms const because we know it does not set + // We make "fma" on GNU or Windows const because we know it does not set // errno in those environments even though it could set errno based on the // C standard. const llvm::Triple &Trip = Context.getTargetInfo().getTriple(); - if ((Trip.isGNUEnvironment() || Trip.isAndroid() || Trip.isOSMSVCRT()) && + if ((Trip.isGNUEnvironment() || Trip.isOSMSVCRT()) && !FD->hasAttr<ConstAttr>()) { switch (BuiltinID) { case Builtin::BI__builtin_fma: @@ -16532,7 +16601,7 @@ CreateNewDecl: SetMemberAccessSpecifier(New, PrevDecl, AS); if (PrevDecl) - CheckRedeclarationModuleOwnership(New, PrevDecl); + CheckRedeclarationInModule(New, PrevDecl); if (TUK == TUK_Definition && (!SkipBody || !SkipBody->ShouldSkip)) New->startDefinition(); @@ -16682,8 +16751,21 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, RD->completeDefinition(); } - if (isa<CXXRecordDecl>(Tag)) { + if (auto *RD = dyn_cast<CXXRecordDecl>(Tag)) { FieldCollector->FinishClass(); + if (RD->hasAttr<SYCLSpecialClassAttr>()) { + auto *Def = RD->getDefinition(); + assert(Def && "The record is expected to have a completed definition"); + unsigned NumInitMethods = 0; + for (auto *Method : Def->methods()) { + if (!Method->getIdentifier()) + continue; + if (Method->getName() == "__init") + NumInitMethods++; + } + if (NumInitMethods > 1 || !Def->hasInitMethod()) + Diag(RD->getLocation(), diag::err_sycl_special_type_num_init_method); + } } // Exit this scope of this tag's definition. @@ -18586,7 +18668,7 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc), AttributeCommonInfo::AS_Pragma); AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit( - Context, AliasName->getName(), /*LiteralLabel=*/true, Info); + Context, AliasName->getName(), /*IsLiteralLabel=*/true, Info); // If a declaration that: // 1) declares a function or a variable diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b6bd2e69629d..f04236ab96c3 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2625,37 +2625,53 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { NewII = &S.Context.Idents.get("watchos_app_extension"); if (NewII) { - auto adjustWatchOSVersion = [](VersionTuple Version) -> VersionTuple { - if (Version.empty()) - return Version; - auto Major = Version.getMajor(); - auto NewMajor = Major >= 9 ? Major - 7 : 0; - if (NewMajor >= 2) { - if (Version.getMinor().hasValue()) { - if (Version.getSubminor().hasValue()) - return VersionTuple(NewMajor, Version.getMinor().getValue(), - Version.getSubminor().getValue()); - else - return VersionTuple(NewMajor, Version.getMinor().getValue()); - } - return VersionTuple(NewMajor); + const auto *SDKInfo = S.getDarwinSDKInfoForAvailabilityChecking(); + const auto *IOSToWatchOSMapping = + SDKInfo ? SDKInfo->getVersionMapping( + DarwinSDKInfo::OSEnvPair::iOStoWatchOSPair()) + : nullptr; + + auto adjustWatchOSVersion = + [IOSToWatchOSMapping](VersionTuple Version) -> VersionTuple { + if (Version.empty()) + return Version; + auto MinimumWatchOSVersion = VersionTuple(2, 0); + + if (IOSToWatchOSMapping) { + if (auto MappedVersion = IOSToWatchOSMapping->map( + Version, MinimumWatchOSVersion, None)) { + return MappedVersion.getValue(); } + } - return VersionTuple(2, 0); - }; + auto Major = Version.getMajor(); + auto NewMajor = Major >= 9 ? Major - 7 : 0; + if (NewMajor >= 2) { + if (Version.getMinor().hasValue()) { + if (Version.getSubminor().hasValue()) + return VersionTuple(NewMajor, Version.getMinor().getValue(), + Version.getSubminor().getValue()); + else + return VersionTuple(NewMajor, Version.getMinor().getValue()); + } + return VersionTuple(NewMajor); + } - auto NewIntroduced = adjustWatchOSVersion(Introduced.Version); - auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version); - auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); + return MinimumWatchOSVersion; + }; - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( - ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, - NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, - Sema::AMK_None, - PriorityModifier + Sema::AP_InferredFromOtherPlatform); - if (NewAttr) - D->addAttr(NewAttr); - } + auto NewIntroduced = adjustWatchOSVersion(Introduced.Version); + auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version); + auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); + + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( + ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, + NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, + Sema::AMK_None, + PriorityModifier + Sema::AP_InferredFromOtherPlatform); + if (NewAttr) + D->addAttr(NewAttr); + } } else if (S.Context.getTargetInfo().getTriple().isTvOS()) { // Transcribe "ios" to "tvos" (and add a new attribute) if the versioning // matches before the start of the tvOS platform. @@ -2666,14 +2682,38 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { NewII = &S.Context.Idents.get("tvos_app_extension"); if (NewII) { + const auto *SDKInfo = S.getDarwinSDKInfoForAvailabilityChecking(); + const auto *IOSToTvOSMapping = + SDKInfo ? SDKInfo->getVersionMapping( + DarwinSDKInfo::OSEnvPair::iOStoTvOSPair()) + : nullptr; + + auto AdjustTvOSVersion = + [IOSToTvOSMapping](VersionTuple Version) -> VersionTuple { + if (Version.empty()) + return Version; + + if (IOSToTvOSMapping) { + if (auto MappedVersion = + IOSToTvOSMapping->map(Version, VersionTuple(0, 0), None)) { + return MappedVersion.getValue(); + } + } + return Version; + }; + + auto NewIntroduced = AdjustTvOSVersion(Introduced.Version); + auto NewDeprecated = AdjustTvOSVersion(Deprecated.Version); + auto NewObsoleted = AdjustTvOSVersion(Obsoleted.Version); + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( - ND, AL, NewII, true /*Implicit*/, Introduced.Version, - Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict, - Replacement, Sema::AMK_None, + ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, + NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, + Sema::AMK_None, PriorityModifier + Sema::AP_InferredFromOtherPlatform); if (NewAttr) D->addAttr(NewAttr); - } + } } else if (S.Context.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS && S.Context.getTargetInfo().getTriple().isMacCatalystEnvironment()) { @@ -8261,6 +8301,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_SYCLKernel: handleSYCLKernelAttr(S, D, AL); break; + case ParsedAttr::AT_SYCLSpecialClass: + handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL); + break; case ParsedAttr::AT_Format: handleFormatAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 01f0079198c7..16cdb7e57723 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -13012,7 +13012,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, NewDecl->setInvalidDecl(); else if (OldDecl) { NewDecl->setPreviousDecl(OldDecl); - CheckRedeclarationModuleOwnership(NewDecl, OldDecl); + CheckRedeclarationInModule(NewDecl, OldDecl); } NewND = NewDecl; diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index d6e659e17069..d4fefc3d18d8 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -2212,9 +2212,8 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, Diag(IVI->getLocation(), diag::err_inconsistent_ivar_count); } -static void WarnUndefinedMethod(Sema &S, SourceLocation ImpLoc, - ObjCMethodDecl *method, - bool &IncompleteImpl, +static void WarnUndefinedMethod(Sema &S, ObjCImplDecl *Impl, + ObjCMethodDecl *method, bool &IncompleteImpl, unsigned DiagID, NamedDecl *NeededFor = nullptr) { // No point warning no definition of method which is 'unavailable'. @@ -2227,10 +2226,19 @@ static void WarnUndefinedMethod(Sema &S, SourceLocation ImpLoc, // separate warnings. We will give that approach a try, as that // matches what we do with protocols. { - const Sema::SemaDiagnosticBuilder &B = S.Diag(ImpLoc, DiagID); + const Sema::SemaDiagnosticBuilder &B = S.Diag(Impl->getLocation(), DiagID); B << method; if (NeededFor) B << NeededFor; + + // Add an empty definition at the end of the @implementation. + std::string FixItStr; + llvm::raw_string_ostream Out(FixItStr); + method->print(Out, Impl->getASTContext().getPrintingPolicy()); + Out << " {\n}\n\n"; + + SourceLocation Loc = Impl->getAtEndRange().getBegin(); + B << FixItHint::CreateInsertion(Loc, FixItStr); } // Issue a note to the original declaration. @@ -2679,14 +2687,10 @@ static void findProtocolsWithExplicitImpls(const ObjCInterfaceDecl *Super, /// CheckProtocolMethodDefs - This routine checks unimplemented methods /// Declared in protocol, and those referenced by it. -static void CheckProtocolMethodDefs(Sema &S, - SourceLocation ImpLoc, - ObjCProtocolDecl *PDecl, - bool& IncompleteImpl, - const Sema::SelectorSet &InsMap, - const Sema::SelectorSet &ClsMap, - ObjCContainerDecl *CDecl, - LazyProtocolNameSet &ProtocolsExplictImpl) { +static void CheckProtocolMethodDefs( + Sema &S, ObjCImplDecl *Impl, ObjCProtocolDecl *PDecl, bool &IncompleteImpl, + const Sema::SelectorSet &InsMap, const Sema::SelectorSet &ClsMap, + ObjCContainerDecl *CDecl, LazyProtocolNameSet &ProtocolsExplictImpl) { ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl); ObjCInterfaceDecl *IDecl = C ? C->getClassInterface() : dyn_cast<ObjCInterfaceDecl>(CDecl); @@ -2773,9 +2777,8 @@ static void CheckProtocolMethodDefs(Sema &S, if (C || MethodInClass->isPropertyAccessor()) continue; unsigned DIAG = diag::warn_unimplemented_protocol_method; - if (!S.Diags.isIgnored(DIAG, ImpLoc)) { - WarnUndefinedMethod(S, ImpLoc, method, IncompleteImpl, DIAG, - PDecl); + if (!S.Diags.isIgnored(DIAG, Impl->getLocation())) { + WarnUndefinedMethod(S, Impl, method, IncompleteImpl, DIAG, PDecl); } } } @@ -2796,15 +2799,15 @@ static void CheckProtocolMethodDefs(Sema &S, continue; unsigned DIAG = diag::warn_unimplemented_protocol_method; - if (!S.Diags.isIgnored(DIAG, ImpLoc)) { - WarnUndefinedMethod(S, ImpLoc, method, IncompleteImpl, DIAG, PDecl); + if (!S.Diags.isIgnored(DIAG, Impl->getLocation())) { + WarnUndefinedMethod(S, Impl, method, IncompleteImpl, DIAG, PDecl); } } } // Check on this protocols's referenced protocols, recursively. for (auto *PI : PDecl->protocols()) - CheckProtocolMethodDefs(S, ImpLoc, PI, IncompleteImpl, InsMap, ClsMap, - CDecl, ProtocolsExplictImpl); + CheckProtocolMethodDefs(S, Impl, PI, IncompleteImpl, InsMap, ClsMap, CDecl, + ProtocolsExplictImpl); } /// MatchAllMethodDeclarations - Check methods declared in interface @@ -2827,7 +2830,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, if (!I->isPropertyAccessor() && !InsMap.count(I->getSelector())) { if (ImmediateClass) - WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl, + WarnUndefinedMethod(*this, IMPDecl, I, IncompleteImpl, diag::warn_undef_method_impl); continue; } else { @@ -2857,7 +2860,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, if (!I->isPropertyAccessor() && !ClsMap.count(I->getSelector())) { if (ImmediateClass) - WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl, + WarnUndefinedMethod(*this, IMPDecl, I, IncompleteImpl, diag::warn_undef_method_impl); } else { ObjCMethodDecl *ImpMethodDecl = @@ -3024,16 +3027,15 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) { for (auto *PI : I->all_referenced_protocols()) - CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), PI, IncompleteImpl, - InsMap, ClsMap, I, ExplicitImplProtocols); + CheckProtocolMethodDefs(*this, IMPDecl, PI, IncompleteImpl, InsMap, + ClsMap, I, ExplicitImplProtocols); } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) { // For extended class, unimplemented methods in its protocols will // be reported in the primary class. if (!C->IsClassExtension()) { for (auto *P : C->protocols()) - CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), P, - IncompleteImpl, InsMap, ClsMap, CDecl, - ExplicitImplProtocols); + CheckProtocolMethodDefs(*this, IMPDecl, P, IncompleteImpl, InsMap, + ClsMap, CDecl, ExplicitImplProtocols); DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, /*SynthesizeProperties=*/false); } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 3af4c6f4bc41..29cb4be7b1ba 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -391,9 +391,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { NewProto->getExtProtoInfo().withExceptionSpec(ESI))); } - if (getLangOpts().MSVCCompat && ESI.Type != EST_DependentNoexcept) { - // Allow missing exception specifications in redeclarations as an extension. - DiagID = diag::ext_ms_missing_exception_specification; + if (getLangOpts().MSVCCompat && isDynamicExceptionSpec(ESI.Type)) { + DiagID = diag::ext_missing_exception_specification; ReturnValueOnError = false; } else if (New->isReplaceableGlobalAllocationFunction() && ESI.Type != EST_DependentNoexcept) { @@ -402,6 +401,10 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { DiagID = diag::ext_missing_exception_specification; ReturnValueOnError = false; } else if (ESI.Type == EST_NoThrow) { + // Don't emit any warning for missing 'nothrow' in MSVC. + if (getLangOpts().MSVCCompat) { + return false; + } // Allow missing attribute 'nothrow' in redeclarations, since this is a very // common omission. DiagID = diag::ext_missing_exception_specification; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d32b3f217aa0..7de43705c2b1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -55,7 +55,6 @@ using namespace clang; using namespace sema; -using llvm::RoundingMode; /// Determine whether the use of this declaration is valid, without /// emitting diagnostics. @@ -4500,6 +4499,10 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, } // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. + if (isUnevaluatedContext() && ExprKind == UETT_SizeOf && + TInfo->getType()->isVariablyModifiedType()) + TInfo = TransformToPotentiallyEvaluated(TInfo); + return new (Context) UnaryExprOrTypeTraitExpr( ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd()); } @@ -4646,6 +4649,38 @@ static bool isMSPropertySubscriptExpr(Sema &S, Expr *Base) { return isa<MSPropertySubscriptExpr>(BaseNoParens); } +// Returns the type used for LHS[RHS], given one of LHS, RHS is type-dependent. +// Typically this is DependentTy, but can sometimes be more precise. +// +// There are cases when we could determine a non-dependent type: +// - LHS and RHS may have non-dependent types despite being type-dependent +// (e.g. unbounded array static members of the current instantiation) +// - one may be a dependent-sized array with known element type +// - one may be a dependent-typed valid index (enum in current instantiation) +// +// We *always* return a dependent type, in such cases it is DependentTy. +// This avoids creating type-dependent expressions with non-dependent types. +// FIXME: is this important to avoid? See https://reviews.llvm.org/D107275 +static QualType getDependentArraySubscriptType(Expr *LHS, Expr *RHS, + const ASTContext &Ctx) { + assert(LHS->isTypeDependent() || RHS->isTypeDependent()); + QualType LTy = LHS->getType(), RTy = RHS->getType(); + QualType Result = Ctx.DependentTy; + if (RTy->isIntegralOrUnscopedEnumerationType()) { + if (const PointerType *PT = LTy->getAs<PointerType>()) + Result = PT->getPointeeType(); + else if (const ArrayType *AT = LTy->getAsArrayTypeUnsafe()) + Result = AT->getElementType(); + } else if (LTy->isIntegralOrUnscopedEnumerationType()) { + if (const PointerType *PT = RTy->getAs<PointerType>()) + Result = PT->getPointeeType(); + else if (const ArrayType *AT = RTy->getAsArrayTypeUnsafe()) + Result = AT->getElementType(); + } + // Ensure we return a dependent type. + return Result->isDependentType() ? Result : Ctx.DependentTy; +} + ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, Expr *idx, SourceLocation rbLoc) { @@ -4738,8 +4773,9 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, // Build an unanalyzed expression if either operand is type-dependent. if (getLangOpts().CPlusPlus && (base->isTypeDependent() || idx->isTypeDependent())) { - return new (Context) ArraySubscriptExpr(base, idx, Context.DependentTy, - VK_LValue, OK_Ordinary, rbLoc); + return new (Context) ArraySubscriptExpr( + base, idx, getDependentArraySubscriptType(base, idx, getASTContext()), + VK_LValue, OK_Ordinary, rbLoc); } // MSDN, property (C++) @@ -5493,7 +5529,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, if (LHSTy->isDependentType() || RHSTy->isDependentType()) { BaseExpr = LHSExp; IndexExpr = RHSExp; - ResultType = Context.DependentTy; + ResultType = + getDependentArraySubscriptType(LHSExp, RHSExp, getASTContext()); } else if (const PointerType *PTy = LHSTy->getAs<PointerType>()) { BaseExpr = LHSExp; IndexExpr = RHSExp; @@ -7694,8 +7731,7 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, CastExpr = Result.get(); } - if (getLangOpts().CPlusPlus && !castType->isVoidType() && - !getSourceManager().isInSystemMacro(LParenLoc)) + if (getLangOpts().CPlusPlus && !castType->isVoidType()) Diag(LParenLoc, diag::warn_old_style_cast) << CastExpr->getSourceRange(); CheckTollFreeBridgeCast(castType, CastExpr); @@ -15913,7 +15949,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // promoted type and the underlying type are the same except for // signedness. Ask the AST for the correctly corresponding type and see // if that's compatible. - if (!PromoteType.isNull() && + if (!PromoteType.isNull() && !UnderlyingType->isBooleanType() && PromoteType->isUnsignedIntegerType() != UnderlyingType->isUnsignedIntegerType()) { UnderlyingType = @@ -16569,6 +16605,16 @@ ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) { return TransformToPE(*this).TransformExpr(E); } +TypeSourceInfo *Sema::TransformToPotentiallyEvaluated(TypeSourceInfo *TInfo) { + assert(isUnevaluatedContext() && + "Should only transform unevaluated expressions"); + ExprEvalContexts.back().Context = + ExprEvalContexts[ExprEvalContexts.size() - 2].Context; + if (isUnevaluatedContext()) + return TInfo; + return TransformToPE(*this).TransformType(TInfo); +} + void Sema::PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, @@ -19176,10 +19222,12 @@ ExprResult Sema::CheckBooleanCondition(SourceLocation Loc, Expr *E, } Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc, - Expr *SubExpr, ConditionKind CK) { - // Empty conditions are valid in for-statements. + Expr *SubExpr, ConditionKind CK, + bool MissingOK) { + // MissingOK indicates whether having no condition expression is valid + // (for loop) or invalid (e.g. while loop). if (!SubExpr) - return ConditionResult(); + return MissingOK ? ConditionResult() : ConditionError(); ExprResult Cond; switch (CK) { @@ -19197,7 +19245,7 @@ Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc, } if (Cond.isInvalid()) { Cond = CreateRecoveryExpr(SubExpr->getBeginLoc(), SubExpr->getEndLoc(), - {SubExpr}); + {SubExpr}, PreferredConditionType(CK)); if (!Cond.get()) return ConditionError(); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 54f0242d2ca1..b34b744d7312 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6614,7 +6614,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, const Type *ClassOrBound; Step(Kind K, const Type *ClassOrBound = nullptr) - : K(K), Quals(), ClassOrBound(ClassOrBound) {} + : K(K), ClassOrBound(ClassOrBound) {} QualType rebuild(ASTContext &Ctx, QualType T) const { T = Ctx.getQualifiedType(T, Quals); switch (K) { @@ -7410,8 +7410,10 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, // the member function body. if (!BaseType->isDependentType() && !isThisOutsideMemberFunctionBody(BaseType) && - RequireCompleteType(OpLoc, BaseType, diag::err_incomplete_member_access)) - return ExprError(); + RequireCompleteType(OpLoc, BaseType, + diag::err_incomplete_member_access)) { + return CreateRecoveryExpr(Base->getBeginLoc(), Base->getEndLoc(), {Base}); + } // C++ [basic.lookup.classref]p2: // If the id-expression in a class member access (5.2.5) is an @@ -7767,7 +7769,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T); - DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc()); + DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc()); + DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd()); TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T); PseudoDestructorTypeStorage Destructed(DestructedTypeInfo); @@ -8697,7 +8700,7 @@ Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS, if (TypeName) { QualType T = CheckTypenameType(ETK_Typename, TypenameKWLoc, SS.getWithLocInContext(Context), *TypeName, - NameLoc, &TSI, /*DeducedTypeContext=*/false); + NameLoc, &TSI, /*DeducedTSTContext=*/false); if (T.isNull()) return nullptr; } else { @@ -8748,7 +8751,7 @@ Sema::ActOnCompoundRequirement( /*HasTypeConstraint=*/true); if (BuildTypeConstraint(SS, TypeConstraint, TParam, - /*EllpsisLoc=*/SourceLocation(), + /*EllipsisLoc=*/SourceLocation(), /*AllowUnexpandedPack=*/true)) // Just produce a requirement with no type requirements. return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, {}); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 83006f9d804a..dfd93aa4638d 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -504,9 +504,12 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, } } - assert(BaseType->isDependentType() || - NameInfo.getName().isDependentName() || - isDependentScopeSpecifier(SS)); + assert(BaseType->isDependentType() || NameInfo.getName().isDependentName() || + isDependentScopeSpecifier(SS) || + (TemplateArgs && llvm::any_of(TemplateArgs->arguments(), + [](const TemplateArgumentLoc &Arg) { + return Arg.getArgument().isDependent(); + }))); // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr // must have pointer type, and the accessed type is the pointee. @@ -1642,6 +1645,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() << FixItHint::CreateReplacement(OpLoc, "->"); + if (S.isSFINAEContext()) + return ExprError(); + // Recurse as an -> access. IsArrow = true; return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index bdc8e1e0b336..4702c405fb4e 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1280,11 +1280,11 @@ static ObjCMethodDecl *findMethodInCurrentClass(Sema &S, Selector Sel) { // whether Sel is potentially direct in this context. if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/true)) return MD; - if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/true)) + if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*Instance=*/true)) return MD; if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/false)) return MD; - if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/false)) + if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*Instance=*/false)) return MD; return nullptr; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 635e93ba8460..af6ee24240ce 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -620,7 +620,7 @@ void LookupResult::resolveKind() { getSema().diagnoseEquivalentInternalLinkageDeclarations( getNameLoc(), HasNonFunction, EquivalentNonFunctions); - Decls.set_size(N); + Decls.truncate(N); if (HasNonFunction && (HasFunction || HasUnresolved)) Ambiguous = true; @@ -4307,18 +4307,35 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { if (!CList.empty() && !CList.back().isResolved()) CList.pop_back(); if (NamedDecl *NewND = Correction.getCorrectionDecl()) { - std::string CorrectionStr = Correction.getAsString(SemaRef.getLangOpts()); - for (TypoResultList::iterator RI = CList.begin(), RIEnd = CList.end(); - RI != RIEnd; ++RI) { - // If the Correction refers to a decl already in the result list, - // replace the existing result if the string representation of Correction - // comes before the current result alphabetically, then stop as there is - // nothing more to be done to add Correction to the candidate set. - if (RI->getCorrectionDecl() == NewND) { - if (CorrectionStr < RI->getAsString(SemaRef.getLangOpts())) - *RI = Correction; - return; - } + auto RI = llvm::find_if(CList, [NewND](const TypoCorrection &TypoCorr) { + return TypoCorr.getCorrectionDecl() == NewND; + }); + if (RI != CList.end()) { + // The Correction refers to a decl already in the list. No insertion is + // necessary and all further cases will return. + + auto IsDeprecated = [](Decl *D) { + while (D) { + if (D->isDeprecated()) + return true; + D = llvm::dyn_cast_or_null<NamespaceDecl>(D->getDeclContext()); + } + return false; + }; + + // Prefer non deprecated Corrections over deprecated and only then + // sort using an alphabetical order. + std::pair<bool, std::string> NewKey = { + IsDeprecated(Correction.getFoundDecl()), + Correction.getAsString(SemaRef.getLangOpts())}; + + std::pair<bool, std::string> PrevKey = { + IsDeprecated(RI->getFoundDecl()), + RI->getAsString(SemaRef.getLangOpts())}; + + if (NewKey < PrevKey) + *RI = Correction; + return; } } if (CList.empty() || Correction.isResolved()) diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index a4b9f3c242c1..747734f2d0ff 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -395,7 +395,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, // [module.interface]p1: // An export-declaration shall inhabit a namespace scope and appear in the // purview of a module interface unit. - Diag(ExportLoc, diag::err_export_not_in_module_interface); + Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0; } return Import; @@ -527,21 +527,30 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, // Set this temporarily so we know the export-declaration was braced. D->setRBraceLoc(LBraceLoc); + CurContext->addDecl(D); + PushDeclContext(S, D); + // C++2a [module.interface]p1: // An export-declaration shall appear only [...] in the purview of a module // interface unit. An export-declaration shall not appear directly or // indirectly within [...] a private-module-fragment. if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) { Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0; + D->setInvalidDecl(); + return D; } else if (!ModuleScopes.back().ModuleInterface) { Diag(ExportLoc, diag::err_export_not_in_module_interface) << 1; Diag(ModuleScopes.back().BeginLoc, diag::note_not_module_interface_add_export) << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); + D->setInvalidDecl(); + return D; } else if (ModuleScopes.back().Module->Kind == Module::PrivateModuleFragment) { Diag(ExportLoc, diag::err_export_in_private_module_fragment); Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment); + D->setInvalidDecl(); + return D; } for (const DeclContext *DC = CurContext; DC; DC = DC->getLexicalParent()) { @@ -553,7 +562,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, Diag(ND->getLocation(), diag::note_anonymous_namespace); // Don't diagnose internal-linkage declarations in this region. D->setInvalidDecl(); - break; + return D; } // A declaration is exported if it is [...] a namespace-definition @@ -572,10 +581,10 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, Diag(ExportLoc, diag::err_export_within_export); if (ED->hasBraces()) Diag(ED->getLocation(), diag::note_export); + D->setInvalidDecl(); + return D; } - CurContext->addDecl(D); - PushDeclContext(S, D); D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported); return D; } diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 74c73ace3c5f..118afb81dd72 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -112,8 +112,8 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop, return; // Look for a property with the same name. - if (ObjCPropertyDecl *ProtoProp = - Proto->lookup(Prop->getDeclName()).find_first<ObjCPropertyDecl>()) { + if (ObjCPropertyDecl *ProtoProp = Proto->getProperty( + Prop->getIdentifier(), Prop->isInstanceProperty())) { S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true); return; } @@ -231,8 +231,8 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, bool FoundInSuper = false; ObjCInterfaceDecl *CurrentInterfaceDecl = IFace; while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) { - if (ObjCPropertyDecl *SuperProp = - Super->lookup(Res->getDeclName()).find_first<ObjCPropertyDecl>()) { + if (ObjCPropertyDecl *SuperProp = Super->getProperty( + Res->getIdentifier(), Res->isInstanceProperty())) { DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false); FoundInSuper = true; break; diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index ba0481874577..ae91a6470471 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -36,6 +36,7 @@ #include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" #include <set> @@ -7051,7 +7052,8 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, QualType AdjustedFnType = FD->getType(); if (NumAppendArgs) { - if (isa<FunctionNoProtoType>(FD->getType())) { + const auto *PTy = AdjustedFnType->getAsAdjusted<FunctionProtoType>(); + if (!PTy) { Diag(FD->getLocation(), diag::err_omp_declare_variant_prototype_required) << SR; return None; @@ -7069,8 +7071,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, Diag(SR.getBegin(), diag::err_omp_interop_type_not_found) << SR; return None; } - QualType InteropType = QualType(TD->getTypeForDecl(), 0); - auto *PTy = cast<FunctionProtoType>(FD->getType()); + QualType InteropType = Context.getTypeDeclType(TD); if (PTy->isVariadic()) { Diag(FD->getLocation(), diag::err_omp_append_args_with_varargs) << SR; return None; @@ -13148,7 +13149,7 @@ StmtResult Sema::ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses, if (FullClause) { if (!VerifyPositiveIntegerConstantInClause( LoopHelper.NumIterations, OMPC_full, /*StrictlyPositive=*/false, - /*SuppressExprDigs=*/true) + /*SuppressExprDiags=*/true) .isUsable()) { Diag(AStmt->getBeginLoc(), diag::err_omp_unroll_full_variable_trip_count); Diag(FullClause->getBeginLoc(), diag::note_omp_directive_here) @@ -20761,8 +20762,7 @@ Sema::ActOnOpenMPEndDeclareTargetDirective() { void Sema::ActOnFinishedOpenMPDeclareTargetContext( DeclareTargetContextInfo &DTCI) { for (auto &It : DTCI.ExplicitlyMapped) - ActOnOpenMPDeclareTargetName(It.first, It.second.Loc, It.second.MT, - DTCI.DT); + ActOnOpenMPDeclareTargetName(It.first, It.second.Loc, It.second.MT, DTCI); } NamedDecl *Sema::lookupOpenMPDeclareTargetName(Scope *CurScope, @@ -20799,9 +20799,9 @@ NamedDecl *Sema::lookupOpenMPDeclareTargetName(Scope *CurScope, return ND; } -void Sema::ActOnOpenMPDeclareTargetName( - NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT, - OMPDeclareTargetDeclAttr::DevTypeTy DT) { +void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc, + OMPDeclareTargetDeclAttr::MapTypeTy MT, + DeclareTargetContextInfo &DTCI) { assert((isa<VarDecl>(ND) || isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND)) && "Expected variable, function or function template."); @@ -20818,10 +20818,10 @@ void Sema::ActOnOpenMPDeclareTargetName( auto *VD = cast<ValueDecl>(ND); llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = OMPDeclareTargetDeclAttr::getActiveAttr(VD); - if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getDevType() != DT && + if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getDevType() != DTCI.DT && ActiveAttr.getValue()->getLevel() == Level) { Diag(Loc, diag::err_omp_device_type_mismatch) - << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DT) + << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DTCI.DT) << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr( ActiveAttr.getValue()->getDevType()); return; @@ -20835,8 +20835,16 @@ void Sema::ActOnOpenMPDeclareTargetName( if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getLevel() == Level) return; - auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT, DT, Level, - SourceRange(Loc, Loc)); + Expr *IndirectE = nullptr; + bool IsIndirect = false; + if (DTCI.Indirect.hasValue()) { + IndirectE = DTCI.Indirect.getValue(); + if (!IndirectE) + IsIndirect = true; + } + auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( + Context, MT, DTCI.DT, IndirectE, IsIndirect, Level, + SourceRange(Loc, Loc)); ND->addAttr(A); if (ASTMutationListener *ML = Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPDeclareTarget(ND, A); @@ -20927,9 +20935,16 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getLevel() >= Level) return; DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back(); + Expr *IndirectE = nullptr; + bool IsIndirect = false; + if (DTCI.Indirect.hasValue()) { + IndirectE = DTCI.Indirect.getValue(); + if (!IndirectE) + IsIndirect = true; + } auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( - Context, OMPDeclareTargetDeclAttr::MT_To, DTCI.DT, Level, - SourceRange(DTCI.Loc, DTCI.Loc)); + Context, OMPDeclareTargetDeclAttr::MT_To, DTCI.DT, IndirectE, + IsIndirect, Level, SourceRange(DTCI.Loc, DTCI.Loc)); D->addAttr(A); if (ASTMutationListener *ML = Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPDeclareTarget(D, A); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 42b1340f9a65..483247aaa7c5 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2405,9 +2405,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType() && !getLangOpts().ObjCAutoRefCount) { ConvertedType = BuildSimilarlyQualifiedPointerType( - FromType->getAs<ObjCObjectPointerType>(), - ToPointeeType, - ToType, Context); + FromType->castAs<ObjCObjectPointerType>(), ToPointeeType, ToType, + Context); return true; } const PointerType *FromTypePtr = FromType->getAs<PointerType>(); @@ -3718,8 +3717,7 @@ compareConversionFunctions(Sema &S, FunctionDecl *Function1, CallingConv Conv2CC = Conv2FuncRet->getCallConv(); CXXMethodDecl *CallOp = Conv2->getParent()->getLambdaCallOperator(); - const FunctionProtoType *CallOpProto = - CallOp->getType()->getAs<FunctionProtoType>(); + const auto *CallOpProto = CallOp->getType()->castAs<FunctionProtoType>(); CallingConv CallOpCC = CallOp->getType()->castAs<FunctionType>()->getCallConv(); @@ -9416,12 +9414,12 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, AddOverloadCandidate( FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, /*AllowExplicit=*/true, - /*AllowExplicitConversions=*/false, ADLCallKind::UsesADL); + /*AllowExplicitConversion=*/false, ADLCallKind::UsesADL); if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) { AddOverloadCandidate( FD, FoundDecl, {Args[1], Args[0]}, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, - /*AllowExplicit=*/true, /*AllowExplicitConversions=*/false, + /*AllowExplicit=*/true, /*AllowExplicitConversion=*/false, ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed); } } else { @@ -14322,8 +14320,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, FoundDecl = MemExpr->getFoundDecl(); Qualifier = MemExpr->getQualifier(); UnbridgedCasts.restore(); - } else { - UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr); + } else if (auto *UnresExpr = dyn_cast<UnresolvedMemberExpr>(NakedMemExpr)) { Qualifier = UnresExpr->getQualifier(); QualType ObjectType = UnresExpr->getBaseType(); @@ -14436,7 +14433,9 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, } MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens()); - } + } else + // Unimaged NakedMemExpr type. + return ExprError(); QualType ResultType = Method->getReturnType(); ExprValueKind VK = Expr::getValueKindForType(ResultType); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 815463307ecc..f8c713c8545d 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -48,3 +48,101 @@ bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { return DiagKind != SemaDiagnosticBuilder::K_Immediate && DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack; } + +static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) { + if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty)) + return CAT->getSize() == 0; + return false; +} + +void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, + llvm::DenseSet<QualType> Visited, + ValueDecl *DeclToCheck) { + assert(getLangOpts().SYCLIsDevice && + "Should only be called during SYCL compilation"); + // Emit notes only for the first discovered declaration of unsupported type + // to avoid mess of notes. This flag is to track that error already happened. + bool NeedToEmitNotes = true; + + auto Check = [&](QualType TypeToCheck, const ValueDecl *D) { + bool ErrorFound = false; + if (isZeroSizedArray(*this, TypeToCheck)) { + SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; + ErrorFound = true; + } + // Checks for other types can also be done here. + if (ErrorFound) { + if (NeedToEmitNotes) { + if (auto *FD = dyn_cast<FieldDecl>(D)) + SYCLDiagIfDeviceCode(FD->getLocation(), + diag::note_illegal_field_declared_here) + << FD->getType()->isPointerType() << FD->getType(); + else + SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at); + } + } + + return ErrorFound; + }; + + // In case we have a Record used do the DFS for a bad field. + SmallVector<const ValueDecl *, 4> StackForRecursion; + StackForRecursion.push_back(DeclToCheck); + + // While doing DFS save how we get there to emit a nice set of notes. + SmallVector<const FieldDecl *, 4> History; + History.push_back(nullptr); + + do { + const ValueDecl *Next = StackForRecursion.pop_back_val(); + if (!Next) { + assert(!History.empty()); + // Found a marker, we have gone up a level. + History.pop_back(); + continue; + } + QualType NextTy = Next->getType(); + + if (!Visited.insert(NextTy).second) + continue; + + auto EmitHistory = [&]() { + // The first element is always nullptr. + for (uint64_t Index = 1; Index < History.size(); ++Index) { + SYCLDiagIfDeviceCode(History[Index]->getLocation(), + diag::note_within_field_of_type) + << History[Index]->getType(); + } + }; + + if (Check(NextTy, Next)) { + if (NeedToEmitNotes) + EmitHistory(); + NeedToEmitNotes = false; + } + + // In case pointer/array/reference type is met get pointee type, then + // proceed with that type. + while (NextTy->isAnyPointerType() || NextTy->isArrayType() || + NextTy->isReferenceType()) { + if (NextTy->isArrayType()) + NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0}; + else + NextTy = NextTy->getPointeeType(); + if (Check(NextTy, Next)) { + if (NeedToEmitNotes) + EmitHistory(); + NeedToEmitNotes = false; + } + } + + if (const auto *RecDecl = NextTy->getAsRecordDecl()) { + if (auto *NextFD = dyn_cast<FieldDecl>(Next)) + History.push_back(NextFD); + // When nullptr is discovered, this means we've gone back up a level, so + // the history should be cleaned. + StackForRecursion.push_back(nullptr); + llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion)); + } + } while (!StackForRecursion.empty()); +} diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 1d90759f2406..746eb82a5bdc 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -410,9 +410,13 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef<Stmt *> Elts, bool isStmtExpr) { const unsigned NumElts = Elts.size(); - // If we're in C89 mode, check that we don't have any decls after stmts. If - // so, emit an extension diagnostic. - if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) { + // If we're in C mode, check that we don't have any decls after stmts. If + // so, emit an extension diagnostic in C89 and potentially a warning in later + // versions. + const unsigned MixedDeclsCodeID = getLangOpts().C99 + ? diag::warn_mixed_decls_code + : diag::ext_mixed_decls_code; + if (!getLangOpts().CPlusPlus && !Diags.isIgnored(MixedDeclsCodeID, L)) { // Note that __extension__ can be around a decl. unsigned i = 0; // Skip over all declarations. @@ -425,7 +429,7 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, if (i != NumElts) { Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin(); - Diag(D->getLocation(), diag::ext_mixed_decls_code); + Diag(D->getLocation(), MixedDeclsCodeID); } } @@ -869,12 +873,7 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, Stmt *thenStmt, SourceLocation ElseLoc, Stmt *elseStmt) { if (Cond.isInvalid()) - Cond = ConditionResult( - *this, nullptr, - MakeFullExpr(new (Context) OpaqueValueExpr(SourceLocation(), - Context.BoolTy, VK_PRValue), - IfLoc), - false); + return StmtError(); bool ConstevalOrNegatedConsteval = StatementKind == IfStatementKind::ConstevalNonNegated || @@ -2468,6 +2467,7 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, Stmt *First, SourceLocation ColonLoc, Expr *Range, SourceLocation RParenLoc, BuildForRangeKind Kind) { + // FIXME: recover in order to allow the body to be parsed. if (!First) return StmtError(); @@ -3878,7 +3878,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, RetValExp, nullptr, /*RecoverUncorrectedTypos=*/true); if (RetVal.isInvalid()) return StmtError(); - StmtResult R = BuildReturnStmt(ReturnLoc, RetVal.get()); + StmtResult R = + BuildReturnStmt(ReturnLoc, RetVal.get(), /*AllowRecovery=*/true); if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext()) return R; @@ -3908,7 +3909,8 @@ static bool CheckSimplerImplicitMovesMSVCWorkaround(const Sema &S, return false; } -StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { +StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, + bool AllowRecovery) { // Check for unexpanded parameter packs. if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); @@ -3985,11 +3987,25 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If we've already decided this function is invalid, e.g. because // we saw a `return` whose expression had an error, don't keep // trying to deduce its return type. - if (FD->isInvalidDecl()) - return StmtError(); - if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { + // (Some return values may be needlessly wrapped in RecoveryExpr). + if (FD->isInvalidDecl() || + DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { FD->setInvalidDecl(); - return StmtError(); + if (!AllowRecovery) + return StmtError(); + // The deduction failure is diagnosed and marked, try to recover. + if (RetValExp) { + // Wrap return value with a recovery expression of the previous type. + // If no deduction yet, use DependentTy. + auto Recovery = CreateRecoveryExpr( + RetValExp->getBeginLoc(), RetValExp->getEndLoc(), RetValExp, + AT->isDeduced() ? FnRetType : QualType()); + if (Recovery.isInvalid()) + return StmtError(); + RetValExp = Recovery.get(); + } else { + // Nothing to do: a ReturnStmt with no value is fine recovery. + } } else { FnRetType = FD->getReturnType(); } @@ -4002,7 +4018,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { ReturnStmt *Result = nullptr; if (FnRetType->isVoidType()) { if (RetValExp) { - if (isa<InitListExpr>(RetValExp)) { + if (auto *ILE = dyn_cast<InitListExpr>(RetValExp)) { // We simply never allow init lists as the return value of void // functions. This is compatible because this was never allowed before, // so there's no legacy code to deal with. @@ -4018,8 +4034,12 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Diag(ReturnLoc, diag::err_return_init_list) << CurDecl << FunctionKind << RetValExp->getSourceRange(); - // Drop the expression. - RetValExp = nullptr; + // Preserve the initializers in the AST. + RetValExp = AllowRecovery + ? CreateRecoveryExpr(ILE->getLBraceLoc(), + ILE->getRBraceLoc(), ILE->inits()) + .get() + : nullptr; } else if (!RetValExp->isTypeDependent()) { // C99 6.8.6.4p1 (ext_ since GCC warns) unsigned D = diag::ext_return_has_expr; @@ -4116,6 +4136,9 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { InitializedEntity::InitializeResult(ReturnLoc, RetType); ExprResult Res = PerformMoveOrCopyInitialization( Entity, NRInfo, RetValExp, SupressSimplerImplicitMoves); + if (Res.isInvalid() && AllowRecovery) + Res = CreateRecoveryExpr(RetValExp->getBeginLoc(), + RetValExp->getEndLoc(), RetValExp, RetType); if (Res.isInvalid()) { // FIXME: Clean up temporaries here anyway? return StmtError(); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 2482f6d404ea..64a0b45feb98 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2063,7 +2063,7 @@ DeclResult Sema::CheckClassTemplate( } if (PrevClassTemplate) - CheckRedeclarationModuleOwnership(NewTemplate, PrevClassTemplate); + CheckRedeclarationInModule(NewTemplate, PrevClassTemplate); if (Invalid) { NewTemplate->setInvalidDecl(); @@ -3672,7 +3672,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, Converted, - /*UpdateArgsWithConversion=*/true)) + /*UpdateArgsWithConversions=*/true)) return QualType(); QualType CanonType; @@ -4318,7 +4318,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, false, Converted, - /*UpdateArgsWithConversion=*/true)) + /*UpdateArgsWithConversions=*/true)) return true; // Find the variable template (partial) specialization declaration that @@ -4489,7 +4489,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, if (CheckTemplateArgumentList( Template, TemplateNameLoc, const_cast<TemplateArgumentListInfo &>(TemplateArgs), false, - Converted, /*UpdateArgsWithConversion=*/true)) + Converted, /*UpdateArgsWithConversions=*/true)) return true; // Produce a placeholder value if the specialization is dependent. @@ -4677,7 +4677,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(), const_cast<TemplateArgumentListInfo&>(*TemplateArgs), /*PartialTemplateArgs=*/false, Converted, - /*UpdateArgsWithConversion=*/false)) + /*UpdateArgsWithConversions=*/false)) return ExprError(); ConstraintSatisfaction Satisfaction; @@ -8343,7 +8343,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, false, Converted, - /*UpdateArgsWithConversion=*/true)) + /*UpdateArgsWithConversions=*/true)) return true; // Find the class template (partial) specialization declaration that @@ -9595,7 +9595,7 @@ DeclResult Sema::ActOnExplicitInstantiation( SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, false, Converted, - /*UpdateArgsWithConversion=*/true)) + /*UpdateArgsWithConversions=*/true)) return true; // Find the class template specialization declaration that diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index e9636d2b942e..22dd395d9943 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -4452,7 +4452,7 @@ namespace { public: SubstituteDeducedTypeTransform(Sema &SemaRef, DependentAuto DA) - : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef), Replacement(), + : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef), ReplacementIsPack(DA.IsPack), UseTypeSugar(true) {} SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 7d4c000e7e90..7c6bb4c8a5f8 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2790,11 +2790,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, CurrentInstantiationScope = I->Scope; // Allow 'this' within late-parsed attributes. - NamedDecl *ND = dyn_cast<NamedDecl>(I->NewDecl); - CXXRecordDecl *ThisContext = - dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext()); + auto *ND = cast<NamedDecl>(I->NewDecl); + auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext()); CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(), - ND && ND->isCXXInstanceMember()); + ND->isCXXInstanceMember()); Attr *NewAttr = instantiateTemplateAttribute(I->TmplAttr, Context, *this, TemplateArgs); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 27ac2cd08f2a..1da0dfec3f23 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3637,7 +3637,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( InstTemplateArgs, false, Converted, - /*UpdateArgsWithConversion=*/true)) + /*UpdateArgsWithConversions=*/true)) return nullptr; // Figure out where to insert this class template explicit specialization @@ -3759,7 +3759,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( SmallVector<TemplateArgument, 4> Converted; if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), VarTemplateArgsInfo, false, Converted, - /*UpdateArgsWithConversion=*/true)) + /*UpdateArgsWithConversions=*/true)) return nullptr; // Check whether we've already seen a declaration of this specialization. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 7a038301a249..959f4903b030 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -22,6 +22,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" @@ -1495,8 +1496,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } case DeclSpec::TST_int128: if (!S.Context.getTargetInfo().hasInt128Type() && - !S.getLangOpts().SYCLIsDevice && - !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + !(S.getLangOpts().SYCLIsDevice || S.getLangOpts().CUDAIsDevice || + (S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice))) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__int128"; if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned) @@ -2515,7 +2516,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Diag(ArraySize->getBeginLoc(), isSFINAEContext() ? diag::err_typecheck_zero_array_size : diag::ext_typecheck_zero_array_size) - << ArraySize->getSourceRange(); + << 0 << ArraySize->getSourceRange(); } // Is the array too large? @@ -5973,6 +5974,11 @@ namespace { Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); TL.setUnderlyingTInfo(TInfo); } + void VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); + TL.setDecltypeLoc(DS.getTypeSpecTypeLoc()); + TL.setRParenLoc(DS.getTypeofParensRange().getEnd()); + } void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { // FIXME: This holds only because we only have one unary transform. assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType); @@ -6036,6 +6042,8 @@ namespace { DS.getTypeSpecType() == TST_auto_type || DS.getTypeSpecType() == TST_unspecified); TL.setNameLoc(DS.getTypeSpecTypeLoc()); + if (DS.getTypeSpecType() == TST_decltype_auto) + TL.setRParenLoc(DS.getTypeofParensRange().getEnd()); if (!DS.isConstrainedAuto()) return; TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 298a3f7a83d8..e43b3ca968eb 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4076,7 +4076,8 @@ Sema::ConditionResult TreeTransform<Derived>::TransformCondition( if (CondExpr.isInvalid()) return Sema::ConditionError(); - return getSema().ActOnCondition(nullptr, Loc, CondExpr.get(), Kind); + return getSema().ActOnCondition(nullptr, Loc, CondExpr.get(), Kind, + /*MissingOK=*/true); } return Sema::ConditionResult(); @@ -6228,15 +6229,15 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || E.get() != T->getUnderlyingExpr()) { - Result = getDerived().RebuildDecltypeType(E.get(), TL.getNameLoc()); + Result = getDerived().RebuildDecltypeType(E.get(), TL.getDecltypeLoc()); if (Result.isNull()) return QualType(); } else E.get(); DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - + NewTL.setDecltypeLoc(TL.getDecltypeLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); return Result; } @@ -6634,6 +6635,7 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, NewTL.setFoundDecl(TL.getFoundDecl()); NewTL.setLAngleLoc(TL.getLAngleLoc()); NewTL.setRAngleLoc(TL.getRAngleLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); for (unsigned I = 0; I < NewTL.getNumArgs(); ++I) NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo()); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index f93e0d2ed1c4..d806fb9e1949 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -142,7 +142,6 @@ using namespace clang; using namespace clang::serialization; using namespace clang::serialization::reader; using llvm::BitstreamCursor; -using llvm::RoundingMode; //===----------------------------------------------------------------------===// // ChainedASTReaderListener implementation @@ -1888,10 +1887,6 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, HFI.isPragmaOnce |= (Flags >> 4) & 0x01; HFI.DirInfo = (Flags >> 1) & 0x07; HFI.IndexHeaderMapHeader = Flags & 0x01; - // FIXME: Find a better way to handle this. Maybe just store a - // "has been included" flag? - HFI.NumIncludes = std::max(endian::readNext<uint16_t, little, unaligned>(d), - HFI.NumIncludes); HFI.ControllingMacroID = Reader.getGlobalIdentifierID( M, endian::readNext<uint32_t, little, unaligned>(d)); if (unsigned FrameworkOffset = @@ -2963,6 +2958,22 @@ ASTReader::ReadControlBlock(ModuleFile &F, } } +void ASTReader::readIncludedFiles(ModuleFile &F, StringRef Blob, + Preprocessor &PP) { + using namespace llvm::support; + + const unsigned char *D = (const unsigned char *)Blob.data(); + unsigned FileCount = endian::readNext<uint32_t, little, unaligned>(D); + + for (unsigned I = 0; I < FileCount; ++I) { + size_t ID = endian::readNext<uint32_t, little, unaligned>(D); + InputFileInfo IFI = readInputFileInfo(F, ID); + if (llvm::ErrorOr<const FileEntry *> File = + PP.getFileManager().getFile(IFI.Filename)) + PP.getIncludedFiles().insert(*File); + } +} + llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { BitstreamCursor &Stream = F.Stream; @@ -3701,6 +3712,10 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, break; } + case PP_INCLUDED_FILES: + readIncludedFiles(F, Blob, PP); + break; + case LATE_PARSED_TEMPLATE: LateParsedTemplates.emplace_back( std::piecewise_construct, std::forward_as_tuple(&F), @@ -4762,11 +4777,11 @@ ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl( break; unsigned Count = Record[0]; const char *Byte = Blob.data(); - F->SearchPathUsage = llvm::BitVector(Count, 0); + F->SearchPathUsage = llvm::BitVector(Count, false); for (unsigned I = 0; I < Count; ++Byte) for (unsigned Bit = 0; Bit < 8 && I < Count; ++Bit, ++I) if (*Byte & (1 << Bit)) - F->SearchPathUsage[I] = 1; + F->SearchPathUsage[I] = true; break; } } @@ -6629,7 +6644,8 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { } void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { - TL.setNameLoc(readSourceLocation()); + TL.setDecltypeLoc(readSourceLocation()); + TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { @@ -6652,6 +6668,8 @@ void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { TL.setArgLocInfo(i, Reader.readTemplateArgumentLocInfo( TL.getTypePtr()->getArg(i).getKind())); } + if (Reader.readBool()) + TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc( diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 2144befcdb14..1ab26e58a404 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2945,391 +2945,6 @@ uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint64_t LocalOffset) { return LocalOffset + M.GlobalBitOffset; } -static bool isSameTemplateParameterList(const ASTContext &C, - const TemplateParameterList *X, - const TemplateParameterList *Y); -static bool isSameEntity(NamedDecl *X, NamedDecl *Y); - -/// Determine whether two template parameters are similar enough -/// that they may be used in declarations of the same template. -static bool isSameTemplateParameter(const NamedDecl *X, - const NamedDecl *Y) { - if (X->getKind() != Y->getKind()) - return false; - - if (const auto *TX = dyn_cast<TemplateTypeParmDecl>(X)) { - const auto *TY = cast<TemplateTypeParmDecl>(Y); - if (TX->isParameterPack() != TY->isParameterPack()) - return false; - if (TX->hasTypeConstraint() != TY->hasTypeConstraint()) - return false; - const TypeConstraint *TXTC = TX->getTypeConstraint(); - const TypeConstraint *TYTC = TY->getTypeConstraint(); - if (!TXTC != !TYTC) - return false; - if (TXTC && TYTC) { - auto *NCX = TXTC->getNamedConcept(); - auto *NCY = TYTC->getNamedConcept(); - if (!NCX || !NCY || !isSameEntity(NCX, NCY)) - return false; - if (TXTC->hasExplicitTemplateArgs() != TYTC->hasExplicitTemplateArgs()) - return false; - if (TXTC->hasExplicitTemplateArgs()) { - const auto *TXTCArgs = TXTC->getTemplateArgsAsWritten(); - const auto *TYTCArgs = TYTC->getTemplateArgsAsWritten(); - if (TXTCArgs->NumTemplateArgs != TYTCArgs->NumTemplateArgs) - return false; - llvm::FoldingSetNodeID XID, YID; - for (const auto &ArgLoc : TXTCArgs->arguments()) - ArgLoc.getArgument().Profile(XID, X->getASTContext()); - for (const auto &ArgLoc : TYTCArgs->arguments()) - ArgLoc.getArgument().Profile(YID, Y->getASTContext()); - if (XID != YID) - return false; - } - } - return true; - } - - if (const auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) { - const auto *TY = cast<NonTypeTemplateParmDecl>(Y); - return TX->isParameterPack() == TY->isParameterPack() && - TX->getASTContext().hasSameType(TX->getType(), TY->getType()); - } - - const auto *TX = cast<TemplateTemplateParmDecl>(X); - const auto *TY = cast<TemplateTemplateParmDecl>(Y); - return TX->isParameterPack() == TY->isParameterPack() && - isSameTemplateParameterList(TX->getASTContext(), - TX->getTemplateParameters(), - TY->getTemplateParameters()); -} - -static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) { - if (auto *NS = X->getAsNamespace()) - return NS; - if (auto *NAS = X->getAsNamespaceAlias()) - return NAS->getNamespace(); - return nullptr; -} - -static bool isSameQualifier(const NestedNameSpecifier *X, - const NestedNameSpecifier *Y) { - if (auto *NSX = getNamespace(X)) { - auto *NSY = getNamespace(Y); - if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl()) - return false; - } else if (X->getKind() != Y->getKind()) - return false; - - // FIXME: For namespaces and types, we're permitted to check that the entity - // is named via the same tokens. We should probably do so. - switch (X->getKind()) { - case NestedNameSpecifier::Identifier: - if (X->getAsIdentifier() != Y->getAsIdentifier()) - return false; - break; - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::NamespaceAlias: - // We've already checked that we named the same namespace. - break; - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: - if (X->getAsType()->getCanonicalTypeInternal() != - Y->getAsType()->getCanonicalTypeInternal()) - return false; - break; - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - return true; - } - - // Recurse into earlier portion of NNS, if any. - auto *PX = X->getPrefix(); - auto *PY = Y->getPrefix(); - if (PX && PY) - return isSameQualifier(PX, PY); - return !PX && !PY; -} - -/// Determine whether two template parameter lists are similar enough -/// that they may be used in declarations of the same template. -static bool isSameTemplateParameterList(const ASTContext &C, - const TemplateParameterList *X, - const TemplateParameterList *Y) { - if (X->size() != Y->size()) - return false; - - for (unsigned I = 0, N = X->size(); I != N; ++I) - if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I))) - return false; - - const Expr *XRC = X->getRequiresClause(); - const Expr *YRC = Y->getRequiresClause(); - if (!XRC != !YRC) - return false; - if (XRC) { - llvm::FoldingSetNodeID XRCID, YRCID; - XRC->Profile(XRCID, C, /*Canonical=*/true); - YRC->Profile(YRCID, C, /*Canonical=*/true); - if (XRCID != YRCID) - return false; - } - - return true; -} - -/// Determine whether the attributes we can overload on are identical for A and -/// B. Will ignore any overloadable attrs represented in the type of A and B. -static bool hasSameOverloadableAttrs(const FunctionDecl *A, - const FunctionDecl *B) { - // Note that pass_object_size attributes are represented in the function's - // ExtParameterInfo, so we don't need to check them here. - - llvm::FoldingSetNodeID Cand1ID, Cand2ID; - auto AEnableIfAttrs = A->specific_attrs<EnableIfAttr>(); - auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>(); - - for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) { - Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair); - Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair); - - // Return false if the number of enable_if attributes is different. - if (!Cand1A || !Cand2A) - return false; - - Cand1ID.clear(); - Cand2ID.clear(); - - (*Cand1A)->getCond()->Profile(Cand1ID, A->getASTContext(), true); - (*Cand2A)->getCond()->Profile(Cand2ID, B->getASTContext(), true); - - // Return false if any of the enable_if expressions of A and B are - // different. - if (Cand1ID != Cand2ID) - return false; - } - return true; -} - -/// Determine whether the two declarations refer to the same entity. -static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { - if (X == Y) - return true; - - if (X->getDeclName() != Y->getDeclName()) - return false; - - // Must be in the same context. - // - // Note that we can't use DeclContext::Equals here, because the DeclContexts - // could be two different declarations of the same function. (We will fix the - // semantic DC to refer to the primary definition after merging.) - if (!declaresSameEntity(cast<Decl>(X->getDeclContext()->getRedeclContext()), - cast<Decl>(Y->getDeclContext()->getRedeclContext()))) - return false; - - // Two typedefs refer to the same entity if they have the same underlying - // type. - if (const auto *TypedefX = dyn_cast<TypedefNameDecl>(X)) - if (const auto *TypedefY = dyn_cast<TypedefNameDecl>(Y)) - return X->getASTContext().hasSameType(TypedefX->getUnderlyingType(), - TypedefY->getUnderlyingType()); - - // Must have the same kind. - if (X->getKind() != Y->getKind()) - return false; - - // Objective-C classes and protocols with the same name always match. - if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X)) - return true; - - if (isa<ClassTemplateSpecializationDecl>(X)) { - // No need to handle these here: we merge them when adding them to the - // template. - return false; - } - - // Compatible tags match. - if (const auto *TagX = dyn_cast<TagDecl>(X)) { - const auto *TagY = cast<TagDecl>(Y); - return (TagX->getTagKind() == TagY->getTagKind()) || - ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class || - TagX->getTagKind() == TTK_Interface) && - (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class || - TagY->getTagKind() == TTK_Interface)); - } - - // Functions with the same type and linkage match. - // FIXME: This needs to cope with merging of prototyped/non-prototyped - // functions, etc. - if (const auto *FuncX = dyn_cast<FunctionDecl>(X)) { - const auto *FuncY = cast<FunctionDecl>(Y); - if (const auto *CtorX = dyn_cast<CXXConstructorDecl>(X)) { - const auto *CtorY = cast<CXXConstructorDecl>(Y); - if (CtorX->getInheritedConstructor() && - !isSameEntity(CtorX->getInheritedConstructor().getConstructor(), - CtorY->getInheritedConstructor().getConstructor())) - return false; - } - - if (FuncX->isMultiVersion() != FuncY->isMultiVersion()) - return false; - - // Multiversioned functions with different feature strings are represented - // as separate declarations. - if (FuncX->isMultiVersion()) { - const auto *TAX = FuncX->getAttr<TargetAttr>(); - const auto *TAY = FuncY->getAttr<TargetAttr>(); - assert(TAX && TAY && "Multiversion Function without target attribute"); - - if (TAX->getFeaturesStr() != TAY->getFeaturesStr()) - return false; - } - - ASTContext &C = FuncX->getASTContext(); - - const Expr *XRC = FuncX->getTrailingRequiresClause(); - const Expr *YRC = FuncY->getTrailingRequiresClause(); - if (!XRC != !YRC) - return false; - if (XRC) { - llvm::FoldingSetNodeID XRCID, YRCID; - XRC->Profile(XRCID, C, /*Canonical=*/true); - YRC->Profile(YRCID, C, /*Canonical=*/true); - if (XRCID != YRCID) - return false; - } - - auto GetTypeAsWritten = [](const FunctionDecl *FD) { - // Map to the first declaration that we've already merged into this one. - // The TSI of redeclarations might not match (due to calling conventions - // being inherited onto the type but not the TSI), but the TSI type of - // the first declaration of the function should match across modules. - FD = FD->getCanonicalDecl(); - return FD->getTypeSourceInfo() ? FD->getTypeSourceInfo()->getType() - : FD->getType(); - }; - QualType XT = GetTypeAsWritten(FuncX), YT = GetTypeAsWritten(FuncY); - if (!C.hasSameType(XT, YT)) { - // We can get functions with different types on the redecl chain in C++17 - // if they have differing exception specifications and at least one of - // the excpetion specs is unresolved. - auto *XFPT = XT->getAs<FunctionProtoType>(); - auto *YFPT = YT->getAs<FunctionProtoType>(); - if (C.getLangOpts().CPlusPlus17 && XFPT && YFPT && - (isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) || - isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) && - C.hasSameFunctionTypeIgnoringExceptionSpec(XT, YT)) - return true; - return false; - } - - return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() && - hasSameOverloadableAttrs(FuncX, FuncY); - } - - // Variables with the same type and linkage match. - if (const auto *VarX = dyn_cast<VarDecl>(X)) { - const auto *VarY = cast<VarDecl>(Y); - if (VarX->getLinkageInternal() == VarY->getLinkageInternal()) { - ASTContext &C = VarX->getASTContext(); - if (C.hasSameType(VarX->getType(), VarY->getType())) - return true; - - // We can get decls with different types on the redecl chain. Eg. - // template <typename T> struct S { static T Var[]; }; // #1 - // template <typename T> T S<T>::Var[sizeof(T)]; // #2 - // Only? happens when completing an incomplete array type. In this case - // when comparing #1 and #2 we should go through their element type. - const ArrayType *VarXTy = C.getAsArrayType(VarX->getType()); - const ArrayType *VarYTy = C.getAsArrayType(VarY->getType()); - if (!VarXTy || !VarYTy) - return false; - if (VarXTy->isIncompleteArrayType() || VarYTy->isIncompleteArrayType()) - return C.hasSameType(VarXTy->getElementType(), VarYTy->getElementType()); - } - return false; - } - - // Namespaces with the same name and inlinedness match. - if (const auto *NamespaceX = dyn_cast<NamespaceDecl>(X)) { - const auto *NamespaceY = cast<NamespaceDecl>(Y); - return NamespaceX->isInline() == NamespaceY->isInline(); - } - - // Identical template names and kinds match if their template parameter lists - // and patterns match. - if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) { - const auto *TemplateY = cast<TemplateDecl>(Y); - return isSameEntity(TemplateX->getTemplatedDecl(), - TemplateY->getTemplatedDecl()) && - isSameTemplateParameterList(TemplateX->getASTContext(), - TemplateX->getTemplateParameters(), - TemplateY->getTemplateParameters()); - } - - // Fields with the same name and the same type match. - if (const auto *FDX = dyn_cast<FieldDecl>(X)) { - const auto *FDY = cast<FieldDecl>(Y); - // FIXME: Also check the bitwidth is odr-equivalent, if any. - return X->getASTContext().hasSameType(FDX->getType(), FDY->getType()); - } - - // Indirect fields with the same target field match. - if (const auto *IFDX = dyn_cast<IndirectFieldDecl>(X)) { - const auto *IFDY = cast<IndirectFieldDecl>(Y); - return IFDX->getAnonField()->getCanonicalDecl() == - IFDY->getAnonField()->getCanonicalDecl(); - } - - // Enumerators with the same name match. - if (isa<EnumConstantDecl>(X)) - // FIXME: Also check the value is odr-equivalent. - return true; - - // Using shadow declarations with the same target match. - if (const auto *USX = dyn_cast<UsingShadowDecl>(X)) { - const auto *USY = cast<UsingShadowDecl>(Y); - return USX->getTargetDecl() == USY->getTargetDecl(); - } - - // Using declarations with the same qualifier match. (We already know that - // the name matches.) - if (const auto *UX = dyn_cast<UsingDecl>(X)) { - const auto *UY = cast<UsingDecl>(Y); - return isSameQualifier(UX->getQualifier(), UY->getQualifier()) && - UX->hasTypename() == UY->hasTypename() && - UX->isAccessDeclaration() == UY->isAccessDeclaration(); - } - if (const auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) { - const auto *UY = cast<UnresolvedUsingValueDecl>(Y); - return isSameQualifier(UX->getQualifier(), UY->getQualifier()) && - UX->isAccessDeclaration() == UY->isAccessDeclaration(); - } - if (const auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X)) { - return isSameQualifier( - UX->getQualifier(), - cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier()); - } - - // Using-pack declarations are only created by instantiation, and match if - // they're instantiated from matching UnresolvedUsing...Decls. - if (const auto *UX = dyn_cast<UsingPackDecl>(X)) { - return declaresSameEntity( - UX->getInstantiatedFromUsingDecl(), - cast<UsingPackDecl>(Y)->getInstantiatedFromUsingDecl()); - } - - // Namespace alias definitions with the same target match. - if (const auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) { - const auto *NAY = cast<NamespaceAliasDecl>(Y); - return NAX->getNamespace()->Equals(NAY->getNamespace()); - } - - return false; -} - /// Find the context in which we should search for previous declarations when /// looking for declarations to merge. DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader, @@ -3511,12 +3126,13 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { return Result; } + ASTContext &C = Reader.getContext(); DeclContext *DC = D->getDeclContext()->getRedeclContext(); if (TypedefNameForLinkage) { auto It = Reader.ImportedTypedefNamesForLinkage.find( std::make_pair(DC, TypedefNameForLinkage)); if (It != Reader.ImportedTypedefNamesForLinkage.end()) - if (isSameEntity(It->second, D)) + if (C.isSameEntity(It->second, D)) return FindExistingResult(Reader, D, It->second, AnonymousDeclNumber, TypedefNameForLinkage); // Go on to check in other places in case an existing typedef name @@ -3528,7 +3144,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { // in its context by number. if (auto *Existing = getAnonymousDeclForMerging( Reader, D->getLexicalDeclContext(), AnonymousDeclNumber)) - if (isSameEntity(Existing, D)) + if (C.isSameEntity(Existing, D)) return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber, TypedefNameForLinkage); } else if (DC->isTranslationUnit() && @@ -3560,7 +3176,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { IEnd = IdResolver.end(); I != IEnd; ++I) { if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage)) - if (isSameEntity(Existing, D)) + if (C.isSameEntity(Existing, D)) return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber, TypedefNameForLinkage); } @@ -3568,7 +3184,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { DeclContext::lookup_result R = MergeDC->noload_lookup(Name); for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) { if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage)) - if (isSameEntity(Existing, D)) + if (C.isSameEntity(Existing, D)) return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber, TypedefNameForLinkage); } @@ -4781,10 +4397,12 @@ void ASTDeclReader::UpdateDecl(Decl *D, case UPD_DECL_MARKED_OPENMP_DECLARETARGET: { auto MapType = Record.readEnum<OMPDeclareTargetDeclAttr::MapTypeTy>(); auto DevType = Record.readEnum<OMPDeclareTargetDeclAttr::DevTypeTy>(); + Expr *IndirectE = Record.readExpr(); + bool Indirect = Record.readBool(); unsigned Level = Record.readInt(); D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit( - Reader.getContext(), MapType, DevType, Level, readSourceRange(), - AttributeCommonInfo::AS_Pragma)); + Reader.getContext(), MapType, DevType, IndirectE, Indirect, Level, + readSourceRange(), AttributeCommonInfo::AS_Pragma)); break; } diff --git a/clang/lib/Serialization/ASTReaderInternals.h b/clang/lib/Serialization/ASTReaderInternals.h index 265a77fdb215..4a4cfcce156d 100644 --- a/clang/lib/Serialization/ASTReaderInternals.h +++ b/clang/lib/Serialization/ASTReaderInternals.h @@ -30,7 +30,6 @@ class ASTReader; class FileEntry; struct HeaderFileInfo; class HeaderSearch; -class IdentifierTable; class ObjCMethodDecl; namespace serialization { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 65a780e67510..763fc9537c04 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -427,7 +427,8 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { } void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { - Record.AddSourceLocation(TL.getNameLoc()); + Record.AddSourceLocation(TL.getDecltypeLoc()); + Record.AddSourceLocation(TL.getRParenLoc()); } void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { @@ -451,6 +452,9 @@ void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) { Record.AddTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(), TL.getArgLocInfo(I)); } + Record.push_back(TL.isDecltypeAuto()); + if (TL.isDecltypeAuto()) + Record.AddSourceLocation(TL.getRParenLoc()); } void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc( @@ -858,6 +862,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH); RECORD(PP_CONDITIONAL_STACK); RECORD(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS); + RECORD(PP_INCLUDED_FILES); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -1769,7 +1774,7 @@ namespace { std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) { unsigned KeyLen = key.Filename.size() + 1 + 8 + 8; - unsigned DataLen = 1 + 2 + 4 + 4; + unsigned DataLen = 1 + 4 + 4; for (auto ModInfo : Data.KnownHeaders) if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) DataLen += 4; @@ -1801,7 +1806,6 @@ namespace { | (Data.HFI.DirInfo << 1) | Data.HFI.IndexHeaderMapHeader; LE.write<uint8_t>(Flags); - LE.write<uint16_t>(Data.HFI.NumIncludes); if (!Data.HFI.ControllingMacro) LE.write<uint32_t>(Data.HFI.ControllingMacroID); @@ -2250,6 +2254,29 @@ static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule, return false; } +void ASTWriter::writeIncludedFiles(raw_ostream &Out, const Preprocessor &PP) { + using namespace llvm::support; + + const Preprocessor::IncludedFilesSet &IncludedFiles = PP.getIncludedFiles(); + + std::vector<uint32_t> IncludedInputFileIDs; + IncludedInputFileIDs.reserve(IncludedFiles.size()); + + for (const FileEntry *File : IncludedFiles) { + auto InputFileIt = InputFileIDs.find(File); + if (InputFileIt == InputFileIDs.end()) + continue; + IncludedInputFileIDs.push_back(InputFileIt->second); + } + + llvm::sort(IncludedInputFileIDs); + + endian::Writer LE(Out, little); + LE.write<uint32_t>(IncludedInputFileIDs.size()); + for (uint32_t ID : IncludedInputFileIDs) + LE.write<uint32_t>(ID); +} + /// Writes the block containing the serialized form of the /// preprocessor. void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { @@ -2458,6 +2485,20 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { MacroOffsetsBase - ASTBlockStartOffset}; Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, bytes(MacroOffsets)); } + + { + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(PP_INCLUDED_FILES)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned IncludedFilesAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + SmallString<2048> Buffer; + raw_svector_ostream Out(Buffer); + writeIncludedFiles(Out, PP); + RecordData::value_type Record[] = {PP_INCLUDED_FILES}; + Stream.EmitRecordWithBlob(IncludedFilesAbbrev, Record, Buffer.data(), + Buffer.size()); + } } void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec, diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp index f4882c7be3f7..4fd217cf7a6e 100644 --- a/clang/lib/Serialization/ModuleManager.cpp +++ b/clang/lib/Serialization/ModuleManager.cpp @@ -304,23 +304,22 @@ ModuleManager::addInMemoryBuffer(StringRef FileName, InMemoryBuffers[Entry] = std::move(Buffer); } -ModuleManager::VisitState *ModuleManager::allocateVisitState() { +std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() { // Fast path: if we have a cached state, use it. if (FirstVisitState) { - VisitState *Result = FirstVisitState; - FirstVisitState = FirstVisitState->NextState; - Result->NextState = nullptr; + auto Result = std::move(FirstVisitState); + FirstVisitState = std::move(Result->NextState); return Result; } // Allocate and return a new state. - return new VisitState(size()); + return std::make_unique<VisitState>(size()); } -void ModuleManager::returnVisitState(VisitState *State) { +void ModuleManager::returnVisitState(std::unique_ptr<VisitState> State) { assert(State->NextState == nullptr && "Visited state is in list?"); - State->NextState = FirstVisitState; - FirstVisitState = State; + State->NextState = std::move(FirstVisitState); + FirstVisitState = std::move(State); } void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) { @@ -351,8 +350,6 @@ ModuleManager::ModuleManager(FileManager &FileMgr, : FileMgr(FileMgr), ModuleCache(&ModuleCache), PCHContainerRdr(PCHContainerRdr), HeaderSearchInfo(HeaderSearchInfo) {} -ModuleManager::~ModuleManager() { delete FirstVisitState; } - void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) { // If the visitation order vector is the wrong size, recompute the order. @@ -396,11 +393,10 @@ void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, assert(VisitOrder.size() == N && "Visitation order is wrong?"); - delete FirstVisitState; FirstVisitState = nullptr; } - VisitState *State = allocateVisitState(); + auto State = allocateVisitState(); unsigned VisitNumber = State->NextVisitNumber++; // If the caller has provided us with a hit-set that came from the global @@ -452,7 +448,7 @@ void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, } while (true); } - returnVisitState(State); + returnVisitState(std::move(State)); } bool ModuleManager::lookupModuleFile(StringRef FileName, off_t ExpectedSize, diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index 7cdd78b8adfb..7841fd82e370 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -302,7 +302,7 @@ class ExplodedGraphViewer : public Checker< check::EndAnalysis > { public: ExplodedGraphViewer() {} void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { - Eng.ViewGraph(0); + Eng.ViewGraph(false); } }; diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index 66ef781871ec..e2209e3debfd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -22,15 +22,14 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "llvm/Support/YAMLTraits.h" -#include <algorithm> #include <limits> #include <memory> -#include <unordered_map> #include <utility> using namespace clang; @@ -38,577 +37,651 @@ using namespace ento; using namespace taint; namespace { -class GenericTaintChecker : public Checker<check::PreCall, check::PostCall> { -public: - static void *getTag() { - static int Tag; - return &Tag; - } - void checkPreCall(const CallEvent &Call, CheckerContext &C) const; - void checkPostCall(const CallEvent &Call, CheckerContext &C) const; +class GenericTaintChecker; - void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, - const char *Sep) const override; +/// Check for CWE-134: Uncontrolled Format String. +constexpr llvm::StringLiteral MsgUncontrolledFormatString = + "Untrusted data is used as a format string " + "(CWE-134: Uncontrolled Format String)"; - using ArgVector = SmallVector<unsigned, 2>; - using SignedArgVector = SmallVector<int, 2>; +/// Check for: +/// CERT/STR02-C. "Sanitize data passed to complex subsystems" +/// CWE-78, "Failure to Sanitize Data into an OS Command" +constexpr llvm::StringLiteral MsgSanitizeSystemArgs = + "Untrusted data is passed to a system call " + "(CERT/STR02-C. Sanitize data passed to complex subsystems)"; - enum class VariadicType { None, Src, Dst }; +/// Check if tainted data is used as a buffer size in strn.. functions, +/// and allocators. +constexpr llvm::StringLiteral MsgTaintedBufferSize = + "Untrusted data is used to specify the buffer size " + "(CERT/STR31-C. Guarantee that storage for strings has sufficient space " + "for character data and the null terminator)"; - /// Used to parse the configuration file. - struct TaintConfiguration { - using NameScopeArgs = std::tuple<std::string, std::string, ArgVector>; +/// Check if tainted data is used as a custom sink's parameter. +constexpr llvm::StringLiteral MsgCustomSink = + "Untrusted data is passed to a user-defined sink"; - struct Propagation { - std::string Name; - std::string Scope; - ArgVector SrcArgs; - SignedArgVector DstArgs; - VariadicType VarType; - unsigned VarIndex; - }; +using ArgIdxTy = int; +using ArgVecTy = llvm::SmallVector<ArgIdxTy, 2>; - std::vector<Propagation> Propagations; - std::vector<NameScopeArgs> Filters; - std::vector<NameScopeArgs> Sinks; +/// Denotes the return value. +constexpr ArgIdxTy ReturnValueIndex{-1}; - TaintConfiguration() = default; - TaintConfiguration(const TaintConfiguration &) = default; - TaintConfiguration(TaintConfiguration &&) = default; - TaintConfiguration &operator=(const TaintConfiguration &) = default; - TaintConfiguration &operator=(TaintConfiguration &&) = default; - }; +static ArgIdxTy fromArgumentCount(unsigned Count) { + assert(Count <= + static_cast<std::size_t>(std::numeric_limits<ArgIdxTy>::max()) && + "ArgIdxTy is not large enough to represent the number of arguments."); + return Count; +} - /// Convert SignedArgVector to ArgVector. - ArgVector convertToArgVector(CheckerManager &Mgr, const std::string &Option, - const SignedArgVector &Args); +/// Check if the region the expression evaluates to is the standard input, +/// and thus, is tainted. +/// FIXME: Move this to Taint.cpp. +bool isStdin(SVal Val, const ASTContext &ACtx) { + // FIXME: What if Val is NonParamVarRegion? - /// Parse the config. - void parseConfiguration(CheckerManager &Mgr, const std::string &Option, - TaintConfiguration &&Config); + // The region should be symbolic, we do not know it's value. + const auto *SymReg = dyn_cast_or_null<SymbolicRegion>(Val.getAsRegion()); + if (!SymReg) + return false; - static const unsigned InvalidArgIndex{std::numeric_limits<unsigned>::max()}; - /// Denotes the return vale. - static const unsigned ReturnValueIndex{std::numeric_limits<unsigned>::max() - - 1}; + // Get it's symbol and find the declaration region it's pointing to. + const auto *Sm = dyn_cast<SymbolRegionValue>(SymReg->getSymbol()); + if (!Sm) + return false; + const auto *DeclReg = dyn_cast<DeclRegion>(Sm->getRegion()); + if (!DeclReg) + return false; -private: - mutable std::unique_ptr<BugType> BT; - void initBugType() const { - if (!BT) - BT = std::make_unique<BugType>(this, "Use of Untrusted Data", - "Untrusted Data"); + // This region corresponds to a declaration, find out if it's a global/extern + // variable named stdin with the proper type. + if (const auto *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) { + D = D->getCanonicalDecl(); + // FIXME: This should look for an exact match. + if (D->getName().contains("stdin") && D->isExternC()) { + const QualType FILETy = ACtx.getFILEType().getCanonicalType(); + const QualType Ty = D->getType().getCanonicalType(); + + if (Ty->isPointerType()) + return Ty->getPointeeType() == FILETy; + } } + return false; +} - struct FunctionData { - FunctionData() = delete; - FunctionData(const FunctionDecl *FDecl, StringRef Name, - std::string FullName) - : FDecl(FDecl), Name(Name), FullName(std::move(FullName)) {} - FunctionData(const FunctionData &) = default; - FunctionData(FunctionData &&) = default; - FunctionData &operator=(const FunctionData &) = delete; - FunctionData &operator=(FunctionData &&) = delete; +SVal getPointeeOf(const CheckerContext &C, Loc LValue) { + const QualType ArgTy = LValue.getType(C.getASTContext()); + if (!ArgTy->isPointerType() || !ArgTy->getPointeeType()->isVoidType()) + return C.getState()->getSVal(LValue); - static Optional<FunctionData> create(const CallEvent &Call, - const CheckerContext &C) { - if (!Call.getDecl()) - return None; + // Do not dereference void pointers. Treat them as byte pointers instead. + // FIXME: we might want to consider more than just the first byte. + return C.getState()->getSVal(LValue, C.getASTContext().CharTy); +} - const FunctionDecl *FDecl = Call.getDecl()->getAsFunction(); - if (!FDecl || (FDecl->getKind() != Decl::Function && - FDecl->getKind() != Decl::CXXMethod)) - return None; +/// Given a pointer/reference argument, return the value it refers to. +Optional<SVal> getPointeeOf(const CheckerContext &C, SVal Arg) { + if (auto LValue = Arg.getAs<Loc>()) + return getPointeeOf(C, *LValue); + return None; +} - StringRef Name = C.getCalleeName(FDecl); - std::string FullName = FDecl->getQualifiedNameAsString(); - if (Name.empty() || FullName.empty()) - return None; +/// Given a pointer, return the SVal of its pointee or if it is tainted, +/// otherwise return the pointer's SVal if tainted. +/// Also considers stdin as a taint source. +Optional<SVal> getTaintedPointeeOrPointer(const CheckerContext &C, SVal Arg) { + const ProgramStateRef State = C.getState(); - return FunctionData{FDecl, Name, std::move(FullName)}; - } + if (auto Pointee = getPointeeOf(C, Arg)) + if (isTainted(State, *Pointee)) // FIXME: isTainted(...) ? Pointee : None; + return Pointee; - bool isInScope(StringRef Scope) const { - return StringRef(FullName).startswith(Scope); - } + if (isTainted(State, Arg)) + return Arg; - const FunctionDecl *const FDecl; - const StringRef Name; - const std::string FullName; - }; + // FIXME: This should be done by the isTainted() API. + if (isStdin(Arg, C.getASTContext())) + return Arg; - /// Catch taint related bugs. Check if tainted data is passed to a - /// system call etc. Returns true on matching. - bool checkPre(const CallEvent &Call, const FunctionData &FData, - CheckerContext &C) const; + return None; +} - /// Add taint sources on a pre-visit. Returns true on matching. - bool addSourcesPre(const CallEvent &Call, const FunctionData &FData, - CheckerContext &C) const; +bool isTaintedOrPointsToTainted(const Expr *E, const ProgramStateRef &State, + CheckerContext &C) { + return getTaintedPointeeOrPointer(C, C.getSVal(E)).hasValue(); +} - /// Mark filter's arguments not tainted on a pre-visit. Returns true on - /// matching. - bool addFiltersPre(const CallEvent &Call, const FunctionData &FData, - CheckerContext &C) const; +/// ArgSet is used to describe arguments relevant for taint detection or +/// taint application. A discrete set of argument indexes and a variadic +/// argument list signified by a starting index are supported. +class ArgSet { +public: + ArgSet() = default; + ArgSet(ArgVecTy &&DiscreteArgs, Optional<ArgIdxTy> VariadicIndex = None) + : DiscreteArgs(std::move(DiscreteArgs)), + VariadicIndex(std::move(VariadicIndex)) {} - /// Propagate taint generated at pre-visit. Returns true on matching. - static bool propagateFromPre(const CallEvent &Call, CheckerContext &C); + bool contains(ArgIdxTy ArgIdx) const { + if (llvm::is_contained(DiscreteArgs, ArgIdx)) + return true; - /// Check if the region the expression evaluates to is the standard input, - /// and thus, is tainted. - static bool isStdin(const Expr *E, CheckerContext &C); + return VariadicIndex && ArgIdx >= *VariadicIndex; + } - /// Given a pointer argument, return the value it points to. - static Optional<SVal> getPointeeOf(CheckerContext &C, const Expr *Arg); + bool isEmpty() const { return DiscreteArgs.empty() && !VariadicIndex; } - /// Check for CWE-134: Uncontrolled Format String. - static constexpr llvm::StringLiteral MsgUncontrolledFormatString = - "Untrusted data is used as a format string " - "(CWE-134: Uncontrolled Format String)"; - bool checkUncontrolledFormatString(const CallEvent &Call, - CheckerContext &C) const; + ArgVecTy ArgsUpTo(ArgIdxTy LastArgIdx) const { + ArgVecTy Args; + for (ArgIdxTy I = ReturnValueIndex; I <= LastArgIdx; ++I) { + if (contains(I)) + Args.push_back(I); + } + return Args; + } - /// Check for: - /// CERT/STR02-C. "Sanitize data passed to complex subsystems" - /// CWE-78, "Failure to Sanitize Data into an OS Command" - static constexpr llvm::StringLiteral MsgSanitizeSystemArgs = - "Untrusted data is passed to a system call " - "(CERT/STR02-C. Sanitize data passed to complex subsystems)"; - bool checkSystemCall(const CallEvent &Call, StringRef Name, - CheckerContext &C) const; +private: + ArgVecTy DiscreteArgs; + Optional<ArgIdxTy> VariadicIndex; +}; - /// Check if tainted data is used as a buffer size ins strn.. functions, - /// and allocators. - static constexpr llvm::StringLiteral MsgTaintedBufferSize = - "Untrusted data is used to specify the buffer size " - "(CERT/STR31-C. Guarantee that storage for strings has sufficient space " - "for character data and the null terminator)"; - bool checkTaintedBufferSize(const CallEvent &Call, CheckerContext &C) const; +/// A struct used to specify taint propagation rules for a function. +/// +/// If any of the possible taint source arguments is tainted, all of the +/// destination arguments should also be tainted. If ReturnValueIndex is added +/// to the dst list, the return value will be tainted. +class GenericTaintRule { + /// Arguments which are taints sinks and should be checked, and a report + /// should be emitted if taint reaches these. + ArgSet SinkArgs; + /// Arguments which should be sanitized on function return. + ArgSet FilterArgs; + /// Arguments which can participate in taint propagationa. If any of the + /// arguments in PropSrcArgs is tainted, all arguments in PropDstArgs should + /// be tainted. + ArgSet PropSrcArgs; + ArgSet PropDstArgs; - /// Check if tainted data is used as a custom sink's parameter. - static constexpr llvm::StringLiteral MsgCustomSink = - "Untrusted data is passed to a user-defined sink"; - bool checkCustomSinks(const CallEvent &Call, const FunctionData &FData, - CheckerContext &C) const; + /// A message that explains why the call is sensitive to taint. + Optional<StringRef> SinkMsg; - /// Generate a report if the expression is tainted or points to tainted data. - bool generateReportIfTainted(const Expr *E, StringRef Msg, - CheckerContext &C) const; + GenericTaintRule() = default; - struct TaintPropagationRule; - template <typename T> - using ConfigDataMap = - std::unordered_multimap<std::string, std::pair<std::string, T>>; - using NameRuleMap = ConfigDataMap<TaintPropagationRule>; - using NameArgMap = ConfigDataMap<ArgVector>; + GenericTaintRule(ArgSet &&Sink, ArgSet &&Filter, ArgSet &&Src, ArgSet &&Dst, + Optional<StringRef> SinkMsg = None) + : SinkArgs(std::move(Sink)), FilterArgs(std::move(Filter)), + PropSrcArgs(std::move(Src)), PropDstArgs(std::move(Dst)), + SinkMsg(SinkMsg) {} - /// Find a function with the given name and scope. Returns the first match - /// or the end of the map. - template <typename T> - static auto findFunctionInConfig(const ConfigDataMap<T> &Map, - const FunctionData &FData); +public: + /// Make a rule that reports a warning if taint reaches any of \p FilterArgs + /// arguments. + static GenericTaintRule Sink(ArgSet &&SinkArgs, + Optional<StringRef> Msg = None) { + return {std::move(SinkArgs), {}, {}, {}, Msg}; + } - /// A struct used to specify taint propagation rules for a function. - /// - /// If any of the possible taint source arguments is tainted, all of the - /// destination arguments should also be tainted. Use InvalidArgIndex in the - /// src list to specify that all of the arguments can introduce taint. Use - /// InvalidArgIndex in the dst arguments to signify that all the non-const - /// pointer and reference arguments might be tainted on return. If - /// ReturnValueIndex is added to the dst list, the return value will be - /// tainted. - struct TaintPropagationRule { - using PropagationFuncType = bool (*)(bool IsTainted, const CallEvent &Call, - CheckerContext &C); + /// Make a rule that sanitizes all FilterArgs arguments. + static GenericTaintRule Filter(ArgSet &&FilterArgs) { + return {{}, std::move(FilterArgs), {}, {}}; + } - /// List of arguments which can be taint sources and should be checked. - ArgVector SrcArgs; - /// List of arguments which should be tainted on function return. - ArgVector DstArgs; - /// Index for the first variadic parameter if exist. - unsigned VariadicIndex; - /// Show when a function has variadic parameters. If it has, it marks all - /// of them as source or destination. - VariadicType VarType; - /// Special function for tainted source determination. If defined, it can - /// override the default behavior. - PropagationFuncType PropagationFunc; + /// Make a rule that unconditionally taints all Args. + /// If Func is provided, it must also return true for taint to propagate. + static GenericTaintRule Source(ArgSet &&SourceArgs) { + return {{}, {}, {}, std::move(SourceArgs)}; + } - TaintPropagationRule() - : VariadicIndex(InvalidArgIndex), VarType(VariadicType::None), - PropagationFunc(nullptr) {} + /// Make a rule that taints all PropDstArgs if any of PropSrcArgs is tainted. + static GenericTaintRule Prop(ArgSet &&SrcArgs, ArgSet &&DstArgs) { + return {{}, {}, std::move(SrcArgs), std::move(DstArgs)}; + } - TaintPropagationRule(ArgVector &&Src, ArgVector &&Dst, - VariadicType Var = VariadicType::None, - unsigned VarIndex = InvalidArgIndex, - PropagationFuncType Func = nullptr) - : SrcArgs(std::move(Src)), DstArgs(std::move(Dst)), - VariadicIndex(VarIndex), VarType(Var), PropagationFunc(Func) {} + /// Make a rule that taints all PropDstArgs if any of PropSrcArgs is tainted. + static GenericTaintRule SinkProp(ArgSet &&SinkArgs, ArgSet &&SrcArgs, + ArgSet &&DstArgs, + Optional<StringRef> Msg = None) { + return { + std::move(SinkArgs), {}, std::move(SrcArgs), std::move(DstArgs), Msg}; + } - /// Get the propagation rule for a given function. - static TaintPropagationRule - getTaintPropagationRule(const NameRuleMap &CustomPropagations, - const FunctionData &FData, CheckerContext &C); + /// Process a function which could either be a taint source, a taint sink, a + /// taint filter or a taint propagator. + void process(const GenericTaintChecker &Checker, const CallEvent &Call, + CheckerContext &C) const; - void addSrcArg(unsigned A) { SrcArgs.push_back(A); } - void addDstArg(unsigned A) { DstArgs.push_back(A); } + /// Handles the resolution of indexes of type ArgIdxTy to Expr*-s. + static const Expr *GetArgExpr(ArgIdxTy ArgIdx, const CallEvent &Call) { + return ArgIdx == ReturnValueIndex ? Call.getOriginExpr() + : Call.getArgExpr(ArgIdx); + }; - bool isNull() const { - return SrcArgs.empty() && DstArgs.empty() && - VariadicType::None == VarType; - } + /// Functions for custom taintedness propagation. + static bool UntrustedEnv(CheckerContext &C); +}; - bool isDestinationArgument(unsigned ArgNum) const { - return llvm::is_contained(DstArgs, ArgNum); - } +using RuleLookupTy = CallDescriptionMap<GenericTaintRule>; - static bool isTaintedOrPointsToTainted(const Expr *E, - const ProgramStateRef &State, - CheckerContext &C) { - if (isTainted(State, E, C.getLocationContext()) || isStdin(E, C)) - return true; +/// Used to parse the configuration file. +struct TaintConfiguration { + using NameScopeArgs = std::tuple<std::string, std::string, ArgVecTy>; + enum class VariadicType { None, Src, Dst }; - if (!E->getType().getTypePtr()->isPointerType()) - return false; + struct Common { + std::string Name; + std::string Scope; + }; - Optional<SVal> V = getPointeeOf(C, E); - return (V && isTainted(State, *V)); - } + struct Sink : Common { + ArgVecTy SinkArgs; + }; - /// Pre-process a function which propagates taint according to the - /// taint rule. - ProgramStateRef process(const CallEvent &Call, CheckerContext &C) const; + struct Filter : Common { + ArgVecTy FilterArgs; + }; - // Functions for custom taintedness propagation. - static bool postSocket(bool IsTainted, const CallEvent &Call, - CheckerContext &C); + struct Propagation : Common { + ArgVecTy SrcArgs; + ArgVecTy DstArgs; + VariadicType VarType; + ArgIdxTy VarIndex; }; - /// Defines a map between the propagation function's name, scope - /// and TaintPropagationRule. - NameRuleMap CustomPropagations; + std::vector<Propagation> Propagations; + std::vector<Filter> Filters; + std::vector<Sink> Sinks; + + TaintConfiguration() = default; + TaintConfiguration(const TaintConfiguration &) = default; + TaintConfiguration(TaintConfiguration &&) = default; + TaintConfiguration &operator=(const TaintConfiguration &) = default; + TaintConfiguration &operator=(TaintConfiguration &&) = default; +}; + +struct GenericTaintRuleParser { + GenericTaintRuleParser(CheckerManager &Mgr) : Mgr(Mgr) {} + /// Container type used to gather call identification objects grouped into + /// pairs with their corresponding taint rules. It is temporary as it is used + /// to finally initialize RuleLookupTy, which is considered to be immutable. + using RulesContTy = std::vector<std::pair<CallDescription, GenericTaintRule>>; + RulesContTy parseConfiguration(const std::string &Option, + TaintConfiguration &&Config) const; - /// Defines a map between the filter function's name, scope and filtering - /// args. - NameArgMap CustomFilters; +private: + using NamePartsTy = llvm::SmallVector<SmallString<32>, 2>; + + /// Validate part of the configuration, which contains a list of argument + /// indexes. + void validateArgVector(const std::string &Option, const ArgVecTy &Args) const; + + template <typename Config> static NamePartsTy parseNameParts(const Config &C); + + // Takes the config and creates a CallDescription for it and associates a Rule + // with that. + template <typename Config> + static void consumeRulesFromConfig(const Config &C, GenericTaintRule &&Rule, + RulesContTy &Rules); + + void parseConfig(const std::string &Option, TaintConfiguration::Sink &&P, + RulesContTy &Rules) const; + void parseConfig(const std::string &Option, TaintConfiguration::Filter &&P, + RulesContTy &Rules) const; + void parseConfig(const std::string &Option, + TaintConfiguration::Propagation &&P, + RulesContTy &Rules) const; - /// Defines a map between the sink function's name, scope and sinking args. - NameArgMap CustomSinks; + CheckerManager &Mgr; }; -const unsigned GenericTaintChecker::ReturnValueIndex; -const unsigned GenericTaintChecker::InvalidArgIndex; +class GenericTaintChecker : public Checker<check::PreCall, check::PostCall> { +public: + static void *getTag() { + static int Tag; + return &Tag; + } -// FIXME: these lines can be removed in C++17 -constexpr llvm::StringLiteral GenericTaintChecker::MsgUncontrolledFormatString; -constexpr llvm::StringLiteral GenericTaintChecker::MsgSanitizeSystemArgs; -constexpr llvm::StringLiteral GenericTaintChecker::MsgTaintedBufferSize; -constexpr llvm::StringLiteral GenericTaintChecker::MsgCustomSink; -} // end of anonymous namespace + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; -using TaintConfig = GenericTaintChecker::TaintConfiguration; + void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, + const char *Sep) const override; -LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::Propagation) -LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameScopeArgs) + /// Generate a report if the expression is tainted or points to tainted data. + bool generateReportIfTainted(const Expr *E, StringRef Msg, + CheckerContext &C) const; + +private: + const BugType BT{this, "Use of Untrusted Data", "Untrusted Data"}; + + bool checkUncontrolledFormatString(const CallEvent &Call, + CheckerContext &C) const; + + void taintUnsafeSocketProtocol(const CallEvent &Call, + CheckerContext &C) const; + + /// Default taint rules are initilized with the help of a CheckerContext to + /// access the names of built-in functions like memcpy. + void initTaintRules(CheckerContext &C) const; + + /// CallDescription currently cannot restrict matches to the global namespace + /// only, which is why multiple CallDescriptionMaps are used, as we want to + /// disambiguate global C functions from functions inside user-defined + /// namespaces. + // TODO: Remove separation to simplify matching logic once CallDescriptions + // are more expressive. + + mutable Optional<RuleLookupTy> StaticTaintRules; + mutable Optional<RuleLookupTy> DynamicTaintRules; +}; +} // end of anonymous namespace + +/// YAML serialization mapping. +LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfiguration::Sink) +LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfiguration::Filter) +LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfiguration::Propagation) namespace llvm { namespace yaml { -template <> struct MappingTraits<TaintConfig> { - static void mapping(IO &IO, TaintConfig &Config) { +template <> struct MappingTraits<TaintConfiguration> { + static void mapping(IO &IO, TaintConfiguration &Config) { IO.mapOptional("Propagations", Config.Propagations); IO.mapOptional("Filters", Config.Filters); IO.mapOptional("Sinks", Config.Sinks); } }; -template <> struct MappingTraits<TaintConfig::Propagation> { - static void mapping(IO &IO, TaintConfig::Propagation &Propagation) { +template <> struct MappingTraits<TaintConfiguration::Sink> { + static void mapping(IO &IO, TaintConfiguration::Sink &Sink) { + IO.mapRequired("Name", Sink.Name); + IO.mapOptional("Scope", Sink.Scope); + IO.mapRequired("Args", Sink.SinkArgs); + } +}; + +template <> struct MappingTraits<TaintConfiguration::Filter> { + static void mapping(IO &IO, TaintConfiguration::Filter &Filter) { + IO.mapRequired("Name", Filter.Name); + IO.mapOptional("Scope", Filter.Scope); + IO.mapRequired("Args", Filter.FilterArgs); + } +}; + +template <> struct MappingTraits<TaintConfiguration::Propagation> { + static void mapping(IO &IO, TaintConfiguration::Propagation &Propagation) { IO.mapRequired("Name", Propagation.Name); IO.mapOptional("Scope", Propagation.Scope); IO.mapOptional("SrcArgs", Propagation.SrcArgs); IO.mapOptional("DstArgs", Propagation.DstArgs); - IO.mapOptional("VariadicType", Propagation.VarType, - GenericTaintChecker::VariadicType::None); - IO.mapOptional("VariadicIndex", Propagation.VarIndex, - GenericTaintChecker::InvalidArgIndex); + IO.mapOptional("VariadicType", Propagation.VarType); + IO.mapOptional("VariadicIndex", Propagation.VarIndex); } }; -template <> struct ScalarEnumerationTraits<GenericTaintChecker::VariadicType> { - static void enumeration(IO &IO, GenericTaintChecker::VariadicType &Value) { - IO.enumCase(Value, "None", GenericTaintChecker::VariadicType::None); - IO.enumCase(Value, "Src", GenericTaintChecker::VariadicType::Src); - IO.enumCase(Value, "Dst", GenericTaintChecker::VariadicType::Dst); - } -}; - -template <> struct MappingTraits<TaintConfig::NameScopeArgs> { - static void mapping(IO &IO, TaintConfig::NameScopeArgs &NSA) { - IO.mapRequired("Name", std::get<0>(NSA)); - IO.mapOptional("Scope", std::get<1>(NSA)); - IO.mapRequired("Args", std::get<2>(NSA)); +template <> struct ScalarEnumerationTraits<TaintConfiguration::VariadicType> { + static void enumeration(IO &IO, TaintConfiguration::VariadicType &Value) { + IO.enumCase(Value, "None", TaintConfiguration::VariadicType::None); + IO.enumCase(Value, "Src", TaintConfiguration::VariadicType::Src); + IO.enumCase(Value, "Dst", TaintConfiguration::VariadicType::Dst); } }; } // namespace yaml } // namespace llvm /// A set which is used to pass information from call pre-visit instruction -/// to the call post-visit. The values are unsigned integers, which are either +/// to the call post-visit. The values are signed integers, which are either /// ReturnValueIndex, or indexes of the pointer/reference argument, which /// points to data, which should be tainted on return. -REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned) +REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, ArgIdxTy) -GenericTaintChecker::ArgVector -GenericTaintChecker::convertToArgVector(CheckerManager &Mgr, - const std::string &Option, - const SignedArgVector &Args) { - ArgVector Result; - for (int Arg : Args) { - if (Arg == -1) - Result.push_back(ReturnValueIndex); - else if (Arg < -1) { - Result.push_back(InvalidArgIndex); +void GenericTaintRuleParser::validateArgVector(const std::string &Option, + const ArgVecTy &Args) const { + for (ArgIdxTy Arg : Args) { + if (Arg < ReturnValueIndex) { Mgr.reportInvalidCheckerOptionValue( - this, Option, + Mgr.getChecker<GenericTaintChecker>(), Option, "an argument number for propagation rules greater or equal to -1"); - } else - Result.push_back(static_cast<unsigned>(Arg)); + } } - return Result; } -void GenericTaintChecker::parseConfiguration(CheckerManager &Mgr, - const std::string &Option, - TaintConfiguration &&Config) { - for (auto &P : Config.Propagations) { - GenericTaintChecker::CustomPropagations.emplace( - P.Name, - std::make_pair(P.Scope, TaintPropagationRule{ - std::move(P.SrcArgs), - convertToArgVector(Mgr, Option, P.DstArgs), - P.VarType, P.VarIndex})); +template <typename Config> +GenericTaintRuleParser::NamePartsTy +GenericTaintRuleParser::parseNameParts(const Config &C) { + NamePartsTy NameParts; + if (!C.Scope.empty()) { + // If the Scope argument contains multiple "::" parts, those are considered + // namespace identifiers. + llvm::SmallVector<StringRef, 2> NSParts; + StringRef{C.Scope}.split(NSParts, "::", /*MaxSplit*/ -1, + /*KeepEmpty*/ false); + NameParts.append(NSParts.begin(), NSParts.end()); } + NameParts.emplace_back(C.Name); + return NameParts; +} - for (auto &F : Config.Filters) { - GenericTaintChecker::CustomFilters.emplace( - std::get<0>(F), - std::make_pair(std::move(std::get<1>(F)), std::move(std::get<2>(F)))); - } +template <typename Config> +void GenericTaintRuleParser::consumeRulesFromConfig(const Config &C, + GenericTaintRule &&Rule, + RulesContTy &Rules) { + NamePartsTy NameParts = parseNameParts(C); + llvm::SmallVector<const char *, 2> CallDescParts{NameParts.size()}; + llvm::transform(NameParts, CallDescParts.begin(), + [](SmallString<32> &S) { return S.c_str(); }); + Rules.emplace_back(CallDescription(CallDescParts), std::move(Rule)); +} - for (auto &S : Config.Sinks) { - GenericTaintChecker::CustomSinks.emplace( - std::get<0>(S), - std::make_pair(std::move(std::get<1>(S)), std::move(std::get<2>(S)))); - } +void GenericTaintRuleParser::parseConfig(const std::string &Option, + TaintConfiguration::Sink &&S, + RulesContTy &Rules) const { + validateArgVector(Option, S.SinkArgs); + consumeRulesFromConfig(S, GenericTaintRule::Sink(std::move(S.SinkArgs)), + Rules); } -template <typename T> -auto GenericTaintChecker::findFunctionInConfig(const ConfigDataMap<T> &Map, - const FunctionData &FData) { - auto Range = Map.equal_range(std::string(FData.Name)); - auto It = - std::find_if(Range.first, Range.second, [&FData](const auto &Entry) { - const auto &Value = Entry.second; - StringRef Scope = Value.first; - return Scope.empty() || FData.isInScope(Scope); - }); - return It != Range.second ? It : Map.end(); +void GenericTaintRuleParser::parseConfig(const std::string &Option, + TaintConfiguration::Filter &&S, + RulesContTy &Rules) const { + validateArgVector(Option, S.FilterArgs); + consumeRulesFromConfig(S, GenericTaintRule::Filter(std::move(S.FilterArgs)), + Rules); } -GenericTaintChecker::TaintPropagationRule -GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( - const NameRuleMap &CustomPropagations, const FunctionData &FData, - CheckerContext &C) { - // TODO: Currently, we might lose precision here: we always mark a return - // value as tainted even if it's just a pointer, pointing to tainted data. +void GenericTaintRuleParser::parseConfig(const std::string &Option, + TaintConfiguration::Propagation &&P, + RulesContTy &Rules) const { + validateArgVector(Option, P.SrcArgs); + validateArgVector(Option, P.DstArgs); + bool IsSrcVariadic = P.VarType == TaintConfiguration::VariadicType::Src; + bool IsDstVariadic = P.VarType == TaintConfiguration::VariadicType::Dst; + Optional<ArgIdxTy> JustVarIndex = P.VarIndex; + + ArgSet SrcDesc(std::move(P.SrcArgs), IsSrcVariadic ? JustVarIndex : None); + ArgSet DstDesc(std::move(P.DstArgs), IsDstVariadic ? JustVarIndex : None); + + consumeRulesFromConfig( + P, GenericTaintRule::Prop(std::move(SrcDesc), std::move(DstDesc)), Rules); +} + +GenericTaintRuleParser::RulesContTy +GenericTaintRuleParser::parseConfiguration(const std::string &Option, + TaintConfiguration &&Config) const { + + RulesContTy Rules; + + for (auto &F : Config.Filters) + parseConfig(Option, std::move(F), Rules); + + for (auto &S : Config.Sinks) + parseConfig(Option, std::move(S), Rules); + + for (auto &P : Config.Propagations) + parseConfig(Option, std::move(P), Rules); + + return Rules; +} +void GenericTaintChecker::initTaintRules(CheckerContext &C) const { // Check for exact name match for functions without builtin substitutes. // Use qualified name, because these are C functions without namespace. - TaintPropagationRule Rule = - llvm::StringSwitch<TaintPropagationRule>(FData.FullName) - // Source functions - // TODO: Add support for vfscanf & family. - .Case("fdopen", {{}, {ReturnValueIndex}}) - .Case("fopen", {{}, {ReturnValueIndex}}) - .Case("freopen", {{}, {ReturnValueIndex}}) - .Case("getch", {{}, {ReturnValueIndex}}) - .Case("getchar", {{}, {ReturnValueIndex}}) - .Case("getchar_unlocked", {{}, {ReturnValueIndex}}) - .Case("gets", {{}, {0, ReturnValueIndex}}) - .Case("scanf", {{}, {}, VariadicType::Dst, 1}) - .Case("socket", {{}, - {ReturnValueIndex}, - VariadicType::None, - InvalidArgIndex, - &TaintPropagationRule::postSocket}) - .Case("wgetch", {{}, {ReturnValueIndex}}) - // Propagating functions - .Case("atoi", {{0}, {ReturnValueIndex}}) - .Case("atol", {{0}, {ReturnValueIndex}}) - .Case("atoll", {{0}, {ReturnValueIndex}}) - .Case("fgetc", {{0}, {ReturnValueIndex}}) - .Case("fgetln", {{0}, {ReturnValueIndex}}) - .Case("fgets", {{2}, {0, ReturnValueIndex}}) - .Case("fscanf", {{0}, {}, VariadicType::Dst, 2}) - .Case("sscanf", {{0}, {}, VariadicType::Dst, 2}) - .Case("getc", {{0}, {ReturnValueIndex}}) - .Case("getc_unlocked", {{0}, {ReturnValueIndex}}) - .Case("getdelim", {{3}, {0}}) - .Case("getline", {{2}, {0}}) - .Case("getw", {{0}, {ReturnValueIndex}}) - .Case("pread", {{0, 1, 2, 3}, {1, ReturnValueIndex}}) - .Case("read", {{0, 2}, {1, ReturnValueIndex}}) - .Case("strchr", {{0}, {ReturnValueIndex}}) - .Case("strrchr", {{0}, {ReturnValueIndex}}) - .Case("tolower", {{0}, {ReturnValueIndex}}) - .Case("toupper", {{0}, {ReturnValueIndex}}) - .Default({}); - if (!Rule.isNull()) - return Rule; + if (StaticTaintRules || DynamicTaintRules) + return; - // `getenv` returns taint only in untrusted environments. - if (FData.FullName == "getenv") { - if (C.getAnalysisManager() - .getAnalyzerOptions() - .ShouldAssumeControlledEnvironment) - return {}; - return {{}, {ReturnValueIndex}}; - } + using RulesConstructionTy = + std::vector<std::pair<CallDescription, GenericTaintRule>>; + using TR = GenericTaintRule; - assert(FData.FDecl); + const Builtin::Context &BI = C.getASTContext().BuiltinInfo; - // Check if it's one of the memory setting/copying functions. - // This check is specialized but faster then calling isCLibraryFunction. - const FunctionDecl *FDecl = FData.FDecl; - unsigned BId = 0; - if ((BId = FDecl->getMemoryFunctionKind())) { - switch (BId) { - case Builtin::BImemcpy: - case Builtin::BImemmove: - case Builtin::BIstrncpy: - case Builtin::BIstrncat: - return {{1, 2}, {0, ReturnValueIndex}}; - case Builtin::BIstrlcpy: - case Builtin::BIstrlcat: - return {{1, 2}, {0}}; - case Builtin::BIstrndup: - return {{0, 1}, {ReturnValueIndex}}; + RulesConstructionTy GlobalCRules{ + // Sources + {{"fdopen"}, TR::Source({{ReturnValueIndex}})}, + {{"fopen"}, TR::Source({{ReturnValueIndex}})}, + {{"freopen"}, TR::Source({{ReturnValueIndex}})}, + {{"getch"}, TR::Source({{ReturnValueIndex}})}, + {{"getchar"}, TR::Source({{ReturnValueIndex}})}, + {{"getchar_unlocked"}, TR::Source({{ReturnValueIndex}})}, + {{"gets"}, TR::Source({{0}, ReturnValueIndex})}, + {{"scanf"}, TR::Source({{}, 1})}, + {{"wgetch"}, TR::Source({{}, ReturnValueIndex})}, - default: - break; - } + // Props + {{"atoi"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"atol"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"atoll"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"fgetc"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"fgetln"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"fgets"}, TR::Prop({{2}}, {{0}, ReturnValueIndex})}, + {{"fscanf"}, TR::Prop({{0}}, {{}, 2})}, + {{"sscanf"}, TR::Prop({{0}}, {{}, 2})}, + {{"getc"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"getc_unlocked"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"getdelim"}, TR::Prop({{3}}, {{0}})}, + {{"getline"}, TR::Prop({{2}}, {{0}})}, + {{"getw"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"pread"}, TR::Prop({{0, 1, 2, 3}}, {{1, ReturnValueIndex}})}, + {{"read"}, TR::Prop({{0, 2}}, {{1, ReturnValueIndex}})}, + {{"strchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"strrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"tolower"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{"toupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncat)}}, + TR::Prop({{1, 2}}, {{0, ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcpy)}}, + TR::Prop({{1, 2}}, {{0}})}, + {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcat)}}, + TR::Prop({{1, 2}}, {{0}})}, + {{CDF_MaybeBuiltin, {"snprintf"}}, + TR::Prop({{1}, 3}, {{0, ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {"sprintf"}}, + TR::Prop({{1}, 2}, {{0, ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {"strcpy"}}, + TR::Prop({{1}}, {{0, ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {"stpcpy"}}, + TR::Prop({{1}}, {{0, ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {"strcat"}}, + TR::Prop({{1}}, {{0, ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {"strdup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {"strdupa"}}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + {{CDF_MaybeBuiltin, {"wcsdup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})}, + + // Sinks + {{"system"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)}, + {{"popen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)}, + {{"execl"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)}, + {{"execle"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)}, + {{"execlp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)}, + {{"execvp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)}, + {{"execvP"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)}, + {{"execve"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)}, + {{"dlopen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)}, + {{CDF_MaybeBuiltin, {"malloc"}}, TR::Sink({{0}}, MsgTaintedBufferSize)}, + {{CDF_MaybeBuiltin, {"calloc"}}, TR::Sink({{0}}, MsgTaintedBufferSize)}, + {{CDF_MaybeBuiltin, {"alloca"}}, TR::Sink({{0}}, MsgTaintedBufferSize)}, + {{CDF_MaybeBuiltin, {"memccpy"}}, TR::Sink({{3}}, MsgTaintedBufferSize)}, + {{CDF_MaybeBuiltin, {"realloc"}}, TR::Sink({{1}}, MsgTaintedBufferSize)}, + {{{"setproctitle"}}, TR::Sink({{0}, 1}, MsgUncontrolledFormatString)}, + {{{"setproctitle_fast"}}, + TR::Sink({{0}, 1}, MsgUncontrolledFormatString)}, + + // SinkProps + {{CDF_MaybeBuiltin, BI.getName(Builtin::BImemcpy)}, + TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}}, + MsgTaintedBufferSize)}, + {{CDF_MaybeBuiltin, {BI.getName(Builtin::BImemmove)}}, + TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}}, + MsgTaintedBufferSize)}, + {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncpy)}}, + TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}}, + MsgTaintedBufferSize)}, + {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrndup)}}, + TR::SinkProp({{1}}, {{0, 1}}, {{ReturnValueIndex}}, + MsgTaintedBufferSize)}, + {{CDF_MaybeBuiltin, {"bcopy"}}, + TR::SinkProp({{2}}, {{0, 2}}, {{1}}, MsgTaintedBufferSize)}}; + + // `getenv` returns taint only in untrusted environments. + if (TR::UntrustedEnv(C)) { + // void setproctitle_init(int argc, char *argv[], char *envp[]) + GlobalCRules.push_back( + {{{"setproctitle_init"}}, TR::Sink({{2}}, MsgCustomSink)}); + GlobalCRules.push_back({{"getenv"}, TR::Source({{ReturnValueIndex}})}); } - // Process all other functions which could be defined as builtins. - if (Rule.isNull()) { - const auto OneOf = [FDecl](const auto &... Name) { - // FIXME: use fold expression in C++17 - using unused = int[]; - bool ret = false; - static_cast<void>(unused{ - 0, (ret |= CheckerContext::isCLibraryFunction(FDecl, Name), 0)...}); - return ret; - }; - if (OneOf("snprintf")) - return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 3}; - if (OneOf("sprintf")) - return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 2}; - if (OneOf("strcpy", "stpcpy", "strcat")) - return {{1}, {0, ReturnValueIndex}}; - if (OneOf("bcopy")) - return {{0, 2}, {1}}; - if (OneOf("strdup", "strdupa", "wcsdup")) - return {{0}, {ReturnValueIndex}}; + StaticTaintRules.emplace(std::make_move_iterator(GlobalCRules.begin()), + std::make_move_iterator(GlobalCRules.end())); + + // User-provided taint configuration. + CheckerManager *Mgr = C.getAnalysisManager().getCheckerManager(); + assert(Mgr); + GenericTaintRuleParser ConfigParser{*Mgr}; + std::string Option{"Config"}; + StringRef ConfigFile = + Mgr->getAnalyzerOptions().getCheckerStringOption(this, Option); + llvm::Optional<TaintConfiguration> Config = + getConfiguration<TaintConfiguration>(*Mgr, this, Option, ConfigFile); + if (!Config) { + // We don't have external taint config, no parsing required. + DynamicTaintRules = RuleLookupTy{}; + return; } - // Skipping the following functions, since they might be used for cleansing or - // smart memory copy: - // - memccpy - copying until hitting a special character. + GenericTaintRuleParser::RulesContTy Rules{ + ConfigParser.parseConfiguration(Option, std::move(Config.getValue()))}; - auto It = findFunctionInConfig(CustomPropagations, FData); - if (It != CustomPropagations.end()) - return It->second.second; - return {}; + DynamicTaintRules.emplace(std::make_move_iterator(Rules.begin()), + std::make_move_iterator(Rules.end())); } void GenericTaintChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - Optional<FunctionData> FData = FunctionData::create(Call, C); - if (!FData) - return; + initTaintRules(C); - // Check for taintedness related errors first: system call, uncontrolled - // format string, tainted buffer size. - if (checkPre(Call, *FData, C)) - return; + // FIXME: this should be much simpler. + if (const auto *Rule = + Call.isGlobalCFunction() ? StaticTaintRules->lookup(Call) : nullptr) + Rule->process(*this, Call, C); + else if (const auto *Rule = DynamicTaintRules->lookup(Call)) + Rule->process(*this, Call, C); - // Marks the function's arguments and/or return value tainted if it present in - // the list. - if (addSourcesPre(Call, *FData, C)) - return; + // FIXME: These edge cases are to be eliminated from here eventually. + // + // Additional check that is not supported by CallDescription. + // TODO: Make CallDescription be able to match attributes such as printf-like + // arguments. + checkUncontrolledFormatString(Call, C); - addFiltersPre(Call, *FData, C); + // TODO: Modeling sockets should be done in a specific checker. + // Socket is a source, which taints the return value. + taintUnsafeSocketProtocol(Call, C); } void GenericTaintChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { // Set the marked values as tainted. The return value only accessible from // checkPostStmt. - propagateFromPre(Call, C); -} - -void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) const { - printTaint(State, Out, NL, Sep); -} - -bool GenericTaintChecker::addSourcesPre(const CallEvent &Call, - const FunctionData &FData, - CheckerContext &C) const { - // First, try generating a propagation rule for this function. - TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule( - this->CustomPropagations, FData, C); - if (!Rule.isNull()) { - ProgramStateRef State = Rule.process(Call, C); - if (State) { - C.addTransition(State); - return true; - } - } - return false; -} - -bool GenericTaintChecker::addFiltersPre(const CallEvent &Call, - const FunctionData &FData, - CheckerContext &C) const { - auto It = findFunctionInConfig(CustomFilters, FData); - if (It == CustomFilters.end()) - return false; - - ProgramStateRef State = C.getState(); - const auto &Value = It->second; - const ArgVector &Args = Value.second; - for (unsigned ArgNum : Args) { - if (ArgNum >= Call.getNumArgs()) - continue; - - const Expr *Arg = Call.getArgExpr(ArgNum); - Optional<SVal> V = getPointeeOf(C, Arg); - if (V) - State = removeTaint(State, *V); - } - - if (State != C.getState()) { - C.addTransition(State); - return true; - } - return false; -} - -bool GenericTaintChecker::propagateFromPre(const CallEvent &Call, - CheckerContext &C) { ProgramStateRef State = C.getState(); // Depending on what was tainted at pre-visit, we determined a set of @@ -616,9 +689,9 @@ bool GenericTaintChecker::propagateFromPre(const CallEvent &Call, // stored in the state as TaintArgsOnPostVisit set. TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>(); if (TaintArgs.isEmpty()) - return false; + return; - for (unsigned ArgNum : TaintArgs) { + for (ArgIdxTy ArgNum : TaintArgs) { // Special handling for the tainted return value. if (ArgNum == ReturnValueIndex) { State = addTaint(State, Call.getReturnValue()); @@ -627,234 +700,147 @@ bool GenericTaintChecker::propagateFromPre(const CallEvent &Call, // The arguments are pointer arguments. The data they are pointing at is // tainted after the call. - if (Call.getNumArgs() < (ArgNum + 1)) - return false; - const Expr *Arg = Call.getArgExpr(ArgNum); - Optional<SVal> V = getPointeeOf(C, Arg); - if (V) + if (auto V = getPointeeOf(C, Call.getArgSVal(ArgNum))) State = addTaint(State, *V); } // Clear up the taint info from the state. State = State->remove<TaintArgsOnPostVisit>(); - - if (State != C.getState()) { - C.addTransition(State); - return true; - } - return false; + C.addTransition(State); } -bool GenericTaintChecker::checkPre(const CallEvent &Call, - const FunctionData &FData, - CheckerContext &C) const { - if (checkUncontrolledFormatString(Call, C)) - return true; - - if (checkSystemCall(Call, FData.Name, C)) - return true; - - if (checkTaintedBufferSize(Call, C)) - return true; - - return checkCustomSinks(Call, FData, C); -} - -Optional<SVal> GenericTaintChecker::getPointeeOf(CheckerContext &C, - const Expr *Arg) { - ProgramStateRef State = C.getState(); - SVal AddrVal = C.getSVal(Arg->IgnoreParens()); - if (AddrVal.isUnknownOrUndef()) - return None; - - Optional<Loc> AddrLoc = AddrVal.getAs<Loc>(); - if (!AddrLoc) - return None; - - QualType ArgTy = Arg->getType().getCanonicalType(); - if (!ArgTy->isPointerType()) - return State->getSVal(*AddrLoc); - - QualType ValTy = ArgTy->getPointeeType(); - - // Do not dereference void pointers. Treat them as byte pointers instead. - // FIXME: we might want to consider more than just the first byte. - if (ValTy->isVoidType()) - ValTy = C.getASTContext().CharTy; - - return State->getSVal(*AddrLoc, ValTy); +void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const { + printTaint(State, Out, NL, Sep); } -ProgramStateRef -GenericTaintChecker::TaintPropagationRule::process(const CallEvent &Call, - CheckerContext &C) const { +void GenericTaintRule::process(const GenericTaintChecker &Checker, + const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); + const ArgIdxTy CallNumArgs = fromArgumentCount(Call.getNumArgs()); - // Check for taint in arguments. - bool IsTainted = true; - for (unsigned ArgNum : SrcArgs) { - if (ArgNum >= Call.getNumArgs()) - continue; + /// Iterate every call argument, and get their corresponding Expr and SVal. + const auto ForEachCallArg = [&C, &Call, CallNumArgs](auto &&Fun) { + for (ArgIdxTy I = ReturnValueIndex; I < CallNumArgs; ++I) { + const Expr *E = GetArgExpr(I, Call); + Fun(I, E, C.getSVal(E)); + } + }; - if ((IsTainted = - isTaintedOrPointsToTainted(Call.getArgExpr(ArgNum), State, C))) - break; - } + /// Check for taint sinks. + ForEachCallArg([this, &Checker, &C, &State](ArgIdxTy I, const Expr *E, SVal) { + if (SinkArgs.contains(I) && isTaintedOrPointsToTainted(E, State, C)) + Checker.generateReportIfTainted(E, SinkMsg.getValueOr(MsgCustomSink), C); + }); - // Check for taint in variadic arguments. - if (!IsTainted && VariadicType::Src == VarType) { - // Check if any of the arguments is tainted - for (unsigned i = VariadicIndex; i < Call.getNumArgs(); ++i) { - if ((IsTainted = - isTaintedOrPointsToTainted(Call.getArgExpr(i), State, C))) - break; + /// Check for taint filters. + ForEachCallArg([this, &C, &State](ArgIdxTy I, const Expr *E, SVal S) { + if (FilterArgs.contains(I)) { + State = removeTaint(State, S); + if (auto P = getPointeeOf(C, S)) + State = removeTaint(State, *P); } - } + }); - if (PropagationFunc) - IsTainted = PropagationFunc(IsTainted, Call, C); + /// Check for taint propagation sources. + /// A rule is relevant if PropSrcArgs is empty, or if any of its signified + /// args are tainted in context of the current CallEvent. + bool IsMatching = PropSrcArgs.isEmpty(); + ForEachCallArg( + [this, &C, &IsMatching, &State](ArgIdxTy I, const Expr *E, SVal) { + IsMatching = IsMatching || (PropSrcArgs.contains(I) && + isTaintedOrPointsToTainted(E, State, C)); + }); - if (!IsTainted) - return State; + if (!IsMatching) + return; - // Mark the arguments which should be tainted after the function returns. - for (unsigned ArgNum : DstArgs) { - // Should mark the return value? - if (ArgNum == ReturnValueIndex) { - State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex); - continue; - } + const auto WouldEscape = [](SVal V, QualType Ty) -> bool { + if (!V.getAs<Loc>()) + return false; - if (ArgNum >= Call.getNumArgs()) - continue; + const bool IsNonConstRef = Ty->isReferenceType() && !Ty.isConstQualified(); + const bool IsNonConstPtr = + Ty->isPointerType() && !Ty->getPointeeType().isConstQualified(); - // Mark the given argument. - State = State->add<TaintArgsOnPostVisit>(ArgNum); - } + return IsNonConstRef || IsNonConstPtr; + }; - // Mark all variadic arguments tainted if present. - if (VariadicType::Dst == VarType) { - // For all pointer and references that were passed in: - // If they are not pointing to const data, mark data as tainted. - // TODO: So far we are just going one level down; ideally we'd need to - // recurse here. - for (unsigned i = VariadicIndex; i < Call.getNumArgs(); ++i) { - const Expr *Arg = Call.getArgExpr(i); - // Process pointer argument. - const Type *ArgTy = Arg->getType().getTypePtr(); - QualType PType = ArgTy->getPointeeType(); - if ((!PType.isNull() && !PType.isConstQualified()) || - (ArgTy->isReferenceType() && !Arg->getType().isConstQualified())) { - State = State->add<TaintArgsOnPostVisit>(i); - } - } - } + /// Propagate taint where it is necessary. + ForEachCallArg( + [this, &State, WouldEscape](ArgIdxTy I, const Expr *E, SVal V) { + if (PropDstArgs.contains(I)) + State = State->add<TaintArgsOnPostVisit>(I); - return State; -} + // TODO: We should traverse all reachable memory regions via the + // escaping parameter. Instead of doing that we simply mark only the + // referred memory region as tainted. + if (WouldEscape(V, E->getType())) + State = State->add<TaintArgsOnPostVisit>(I); + }); -// If argument 0(protocol domain) is network, the return value should get taint. -bool GenericTaintChecker::TaintPropagationRule::postSocket( - bool /*IsTainted*/, const CallEvent &Call, CheckerContext &C) { - SourceLocation DomLoc = Call.getArgExpr(0)->getExprLoc(); - StringRef DomName = C.getMacroNameOrSpelling(DomLoc); - // White list the internal communication protocols. - if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") || - DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36")) - return false; - return true; + C.addTransition(State); } -bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) { - ProgramStateRef State = C.getState(); - SVal Val = C.getSVal(E); +bool GenericTaintRule::UntrustedEnv(CheckerContext &C) { + return !C.getAnalysisManager() + .getAnalyzerOptions() + .ShouldAssumeControlledEnvironment; +} - // stdin is a pointer, so it would be a region. - const MemRegion *MemReg = Val.getAsRegion(); +bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg, + CheckerContext &C) const { + assert(E); + Optional<SVal> TaintedSVal{getTaintedPointeeOrPointer(C, C.getSVal(E))}; - // The region should be symbolic, we do not know it's value. - const auto *SymReg = dyn_cast_or_null<SymbolicRegion>(MemReg); - if (!SymReg) + if (!TaintedSVal) return false; - // Get it's symbol and find the declaration region it's pointing to. - const auto *Sm = dyn_cast<SymbolRegionValue>(SymReg->getSymbol()); - if (!Sm) - return false; - const auto *DeclReg = dyn_cast_or_null<DeclRegion>(Sm->getRegion()); - if (!DeclReg) - return false; - - // This region corresponds to a declaration, find out if it's a global/extern - // variable named stdin with the proper type. - if (const auto *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) { - D = D->getCanonicalDecl(); - if (D->getName().contains("stdin") && D->isExternC()) { - const auto *PtrTy = dyn_cast<PointerType>(D->getType().getTypePtr()); - if (PtrTy && PtrTy->getPointeeType().getCanonicalType() == - C.getASTContext().getFILEType().getCanonicalType()) - return true; - } + // Generate diagnostic. + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { + auto report = std::make_unique<PathSensitiveBugReport>(BT, Msg, N); + report->addRange(E->getSourceRange()); + report->addVisitor(std::make_unique<TaintBugVisitor>(*TaintedSVal)); + C.emitReport(std::move(report)); + return true; } return false; } +/// TODO: remove checking for printf format attributes and socket whitelisting +/// from GenericTaintChecker, and that means the following functions: +/// getPrintfFormatArgumentNum, +/// GenericTaintChecker::checkUncontrolledFormatString, +/// GenericTaintChecker::taintUnsafeSocketProtocol + static bool getPrintfFormatArgumentNum(const CallEvent &Call, const CheckerContext &C, - unsigned &ArgNum) { + ArgIdxTy &ArgNum) { // Find if the function contains a format string argument. // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf, // vsnprintf, syslog, custom annotated functions. - const FunctionDecl *FDecl = Call.getDecl()->getAsFunction(); + const Decl *CallDecl = Call.getDecl(); + if (!CallDecl) + return false; + const FunctionDecl *FDecl = CallDecl->getAsFunction(); if (!FDecl) return false; + + const ArgIdxTy CallNumArgs = fromArgumentCount(Call.getNumArgs()); + for (const auto *Format : FDecl->specific_attrs<FormatAttr>()) { ArgNum = Format->getFormatIdx() - 1; - if ((Format->getType()->getName() == "printf") && - Call.getNumArgs() > ArgNum) + if ((Format->getType()->getName() == "printf") && CallNumArgs > ArgNum) return true; } - // Or if a function is named setproctitle (this is a heuristic). - if (C.getCalleeName(FDecl).contains("setproctitle")) { - ArgNum = 0; - return true; - } - - return false; -} - -bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg, - CheckerContext &C) const { - assert(E); - - // Check for taint. - ProgramStateRef State = C.getState(); - Optional<SVal> PointedToSVal = getPointeeOf(C, E); - SVal TaintedSVal; - if (PointedToSVal && isTainted(State, *PointedToSVal)) - TaintedSVal = *PointedToSVal; - else if (isTainted(State, E, C.getLocationContext())) - TaintedSVal = C.getSVal(E); - else - return false; - - // Generate diagnostic. - if (ExplodedNode *N = C.generateNonFatalErrorNode()) { - initBugType(); - auto report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N); - report->addRange(E->getSourceRange()); - report->addVisitor(std::make_unique<TaintBugVisitor>(TaintedSVal)); - C.emitReport(std::move(report)); - return true; - } return false; } bool GenericTaintChecker::checkUncontrolledFormatString( const CallEvent &Call, CheckerContext &C) const { // Check if the function contains a format string argument. - unsigned ArgNum = 0; + ArgIdxTy ArgNum = 0; if (!getPrintfFormatArgumentNum(Call, C, ArgNum)) return false; @@ -864,102 +850,32 @@ bool GenericTaintChecker::checkUncontrolledFormatString( MsgUncontrolledFormatString, C); } -bool GenericTaintChecker::checkSystemCall(const CallEvent &Call, StringRef Name, - CheckerContext &C) const { - // TODO: It might make sense to run this check on demand. In some cases, - // we should check if the environment has been cleansed here. We also might - // need to know if the user was reset before these calls(seteuid). - unsigned ArgNum = llvm::StringSwitch<unsigned>(Name) - .Case("system", 0) - .Case("popen", 0) - .Case("execl", 0) - .Case("execle", 0) - .Case("execlp", 0) - .Case("execv", 0) - .Case("execvp", 0) - .Case("execvP", 0) - .Case("execve", 0) - .Case("dlopen", 0) - .Default(InvalidArgIndex); - - if (ArgNum == InvalidArgIndex || Call.getNumArgs() < (ArgNum + 1)) - return false; - - return generateReportIfTainted(Call.getArgExpr(ArgNum), MsgSanitizeSystemArgs, - C); -} - -// TODO: Should this check be a part of the CString checker? -// If yes, should taint be a global setting? -bool GenericTaintChecker::checkTaintedBufferSize(const CallEvent &Call, - CheckerContext &C) const { - const auto *FDecl = Call.getDecl()->getAsFunction(); - // If the function has a buffer size argument, set ArgNum. - unsigned ArgNum = InvalidArgIndex; - unsigned BId = 0; - if ((BId = FDecl->getMemoryFunctionKind())) { - switch (BId) { - case Builtin::BImemcpy: - case Builtin::BImemmove: - case Builtin::BIstrncpy: - ArgNum = 2; - break; - case Builtin::BIstrndup: - ArgNum = 1; - break; - default: - break; - } - } +void GenericTaintChecker::taintUnsafeSocketProtocol(const CallEvent &Call, + CheckerContext &C) const { + if (Call.getNumArgs() < 1) + return; + const IdentifierInfo *ID = Call.getCalleeIdentifier(); + if (!ID) + return; + if (!ID->getName().equals("socket")) + return; - if (ArgNum == InvalidArgIndex) { - using CCtx = CheckerContext; - if (CCtx::isCLibraryFunction(FDecl, "malloc") || - CCtx::isCLibraryFunction(FDecl, "calloc") || - CCtx::isCLibraryFunction(FDecl, "alloca")) - ArgNum = 0; - else if (CCtx::isCLibraryFunction(FDecl, "memccpy")) - ArgNum = 3; - else if (CCtx::isCLibraryFunction(FDecl, "realloc")) - ArgNum = 1; - else if (CCtx::isCLibraryFunction(FDecl, "bcopy")) - ArgNum = 2; - } + SourceLocation DomLoc = Call.getArgExpr(0)->getExprLoc(); + StringRef DomName = C.getMacroNameOrSpelling(DomLoc); + // Allow internal communication protocols. + bool SafeProtocol = DomName.equals("AF_SYSTEM") || + DomName.equals("AF_LOCAL") || DomName.equals("AF_UNIX") || + DomName.equals("AF_RESERVED_36"); + if (SafeProtocol) + return; - return ArgNum != InvalidArgIndex && Call.getNumArgs() > ArgNum && - generateReportIfTainted(Call.getArgExpr(ArgNum), MsgTaintedBufferSize, - C); + C.addTransition(C.getState()->add<TaintArgsOnPostVisit>(ReturnValueIndex)); } -bool GenericTaintChecker::checkCustomSinks(const CallEvent &Call, - const FunctionData &FData, - CheckerContext &C) const { - auto It = findFunctionInConfig(CustomSinks, FData); - if (It == CustomSinks.end()) - return false; - - const auto &Value = It->second; - const GenericTaintChecker::ArgVector &Args = Value.second; - for (unsigned ArgNum : Args) { - if (ArgNum >= Call.getNumArgs()) - continue; - - if (generateReportIfTainted(Call.getArgExpr(ArgNum), MsgCustomSink, C)) - return true; - } - - return false; -} +/// Checker registration void ento::registerGenericTaintChecker(CheckerManager &Mgr) { - auto *Checker = Mgr.registerChecker<GenericTaintChecker>(); - std::string Option{"Config"}; - StringRef ConfigFile = - Mgr.getAnalyzerOptions().getCheckerStringOption(Checker, Option); - llvm::Optional<TaintConfig> Config = - getConfiguration<TaintConfig>(Mgr, Checker, Option, ConfigFile); - if (Config) - Checker->parseConfiguration(Mgr, Option, std::move(Config.getValue())); + Mgr.registerChecker<GenericTaintChecker>(); } bool ento::shouldRegisterGenericTaintChecker(const CheckerManager &mgr) { diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 10ed6149528c..57080a84451a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1643,7 +1643,7 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call, ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0), Call, C.getState(), /*Hold=*/true, IsKnownToBeAllocatedMemory, AF_Malloc, - /*RetNullOnFailure=*/true); + /*ReturnsNullOnFailure=*/true); C.addTransition(State); } diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp index 517a5d78271b..aa70db041c76 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp @@ -23,7 +23,6 @@ using namespace clang; using namespace ento; -using llvm::APSInt; namespace { class MmapWriteExecChecker : public Checker<check::PreCall> { diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp index cd502241ef61..cf97439a468d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp @@ -59,7 +59,7 @@ private: } // namespace static std::string getName(const CallEvent &Call) { - std::string Name = ""; + std::string Name; if (const auto *MD = dyn_cast<CXXMethodDecl>(Call.getDecl())) if (const CXXRecordDecl *RD = MD->getParent()) Name += RD->getNameAsString() + "::"; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h index ec6a7144fa45..e35ea4ef05dd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h @@ -17,10 +17,6 @@ #include <utility> namespace clang { -class CXXRecordDecl; -class CXXBaseSpecifier; -class FunctionDecl; -class CXXMethodDecl; class Expr; /// This function de-facto defines a set of transformations that we consider diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index 730a59977175..753adea0d14d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -15,7 +15,6 @@ namespace clang { class CXXBaseSpecifier; class CXXMethodDecl; class CXXRecordDecl; -class Expr; class FunctionDecl; class Type; diff --git a/clang/lib/StaticAnalyzer/Checkers/Yaml.h b/clang/lib/StaticAnalyzer/Checkers/Yaml.h index ec612dde3b8b..497189f4c160 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Yaml.h +++ b/clang/lib/StaticAnalyzer/Checkers/Yaml.h @@ -57,4 +57,4 @@ llvm::Optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk, } // namespace ento } // namespace clang -#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MOVE_H +#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKER_YAML_H diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index b957bec7493e..e13387fb1fc8 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -2804,7 +2804,8 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, Out << '\'' << Lexer::getSourceText( CharSourceRange::getTokenRange(Ex->getSourceRange()), - BRC.getSourceManager(), BRC.getASTContext().getLangOpts(), 0) + BRC.getSourceManager(), BRC.getASTContext().getLangOpts(), + nullptr) << '\''; } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 637e4edfd778..302a971a15f2 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -416,7 +416,10 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_IntegralCast: { // Delegate to SValBuilder to process. SVal V = state->getSVal(Ex, LCtx); - V = svalBuilder.evalIntegralCast(state, V, T, ExTy); + if (AMgr.options.ShouldSupportSymbolicIntegerCasts) + V = svalBuilder.evalCast(V, T, ExTy); + else + V = svalBuilder.evalIntegralCast(state, V, T, ExTy); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 1ccb0de92fba..8d4e0bbb7dec 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -54,11 +54,7 @@ ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env, } ProgramState::ProgramState(const ProgramState &RHS) - : llvm::FoldingSetNode(), - stateMgr(RHS.stateMgr), - Env(RHS.Env), - store(RHS.store), - GDM(RHS.GDM), + : stateMgr(RHS.stateMgr), Env(RHS.Env), store(RHS.store), GDM(RHS.GDM), refCount(0) { stateMgr->getStoreManager().incrementReferenceCount(store); } diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index 8edcef319088..bb3261bae3bf 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -980,15 +980,19 @@ SVal SValBuilder::evalCastSubKind(nonloc::SymbolVal V, QualType CastTy, } else { // Symbol to integer, float. QualType T = Context.getCanonicalType(SE->getType()); - // If types are the same or both are integers, ignore the cast. - // FIXME: Remove this hack when we support symbolic truncation/extension. - // HACK: If both castTy and T are integers, ignore the cast. This is - // not a permanent solution. Eventually we want to precisely handle - // extension/truncation of symbolic integers. This prevents us from losing - // precision when we assign 'x = y' and 'y' is symbolic and x and y are - // different integer types. - if (haveSameType(T, CastTy)) - return V; + + // Produce SymbolCast if CastTy and T are different integers. + // NOTE: In the end the type of SymbolCast shall be equal to CastTy. + if (T->isIntegralOrEnumerationType() && + CastTy->isIntegralOrEnumerationType()) { + AnalyzerOptions &Opts = + StateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions(); + // If appropriate option is disabled, ignore the cast. + // NOTE: ShouldSupportSymbolicIntegerCasts is `false` by default. + if (!Opts.ShouldSupportSymbolicIntegerCasts) + return V; + return simplifySymbolCast(V, CastTy); + } if (!Loc::isLocType(CastTy)) if (!IsUnknownOriginalType || !CastTy->isFloatingType() || T->isFloatingType()) @@ -1004,3 +1008,75 @@ SVal SValBuilder::evalCastSubKind(nonloc::PointerToMember V, QualType CastTy, // Member pointer to whatever. return V; } + +SVal clang::ento::SValBuilder::simplifySymbolCast(nonloc::SymbolVal V, + QualType CastTy) { + // We use seven conditions to recognize a simplification case. + // For the clarity let `CastTy` be `C`, SE->getType() - `T`, root type - `R`, + // prefix `u` for unsigned, `s` for signed, no prefix - any sign: + // E.g. (char)(short)(uint x) + // ( sC )( sT )( uR x) + // + // C === R (the same type) + // (char)(char x) -> (char x) + // (long)(long x) -> (long x) + // Note: Comparisons operators below are for bit width. + // C == T + // (short)(short)(int x) -> (short)(int x) + // (int)(long)(char x) -> (int)(char x) (sizeof(long) == sizeof(int)) + // (long)(ullong)(char x) -> (long)(char x) (sizeof(long) == sizeof(ullong)) + // C < T + // (short)(int)(char x) -> (short)(char x) + // (char)(int)(short x) -> (char)(short x) + // (short)(int)(short x) -> (short x) + // C > T > uR + // (int)(short)(uchar x) -> (int)(uchar x) + // (uint)(short)(uchar x) -> (uint)(uchar x) + // (int)(ushort)(uchar x) -> (int)(uchar x) + // C > sT > sR + // (int)(short)(char x) -> (int)(char x) + // (uint)(short)(char x) -> (uint)(char x) + // C > sT == sR + // (int)(char)(char x) -> (int)(char x) + // (uint)(short)(short x) -> (uint)(short x) + // C > uT == uR + // (int)(uchar)(uchar x) -> (int)(uchar x) + // (uint)(ushort)(ushort x) -> (uint)(ushort x) + // (llong)(ulong)(uint x) -> (llong)(uint x) (sizeof(ulong) == sizeof(uint)) + + SymbolRef SE = V.getSymbol(); + QualType T = Context.getCanonicalType(SE->getType()); + + if (T == CastTy) + return V; + + if (!isa<SymbolCast>(SE)) + return makeNonLoc(SE, T, CastTy); + + SymbolRef RootSym = cast<SymbolCast>(SE)->getOperand(); + QualType RT = RootSym->getType().getCanonicalType(); + + BasicValueFactory &BVF = getBasicValueFactory(); + APSIntType CTy = BVF.getAPSIntType(CastTy); + APSIntType TTy = BVF.getAPSIntType(T); + + const auto WC = CTy.getBitWidth(); + const auto WT = TTy.getBitWidth(); + + if (WC <= WT) { + const bool isSameType = (RT == CastTy); + if (isSameType) + return nonloc::SymbolVal(RootSym); + return makeNonLoc(RootSym, RT, CastTy); + } + + APSIntType RTy = BVF.getAPSIntType(RT); + const auto WR = RTy.getBitWidth(); + const bool UT = TTy.isUnsigned(); + const bool UR = RTy.isUnsigned(); + + if (((WT > WR) && (UR || !UT)) || ((WT == WR) && (UT == UR))) + return makeNonLoc(RootSym, RT, CastTy); + + return makeNonLoc(SE, T, CastTy); +} diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index dad8a7b3caae..0bd47ced15a5 100644 --- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -432,7 +432,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, return evalCast(lhs, resultTy, QualType{}); } - while (1) { + while (true) { switch (lhs.getSubKind()) { default: return makeSymExprValNN(op, lhs, rhs, resultTy); diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index f6ddcb763f9d..b152f9d80ef5 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -143,7 +143,7 @@ public: } if (Opts->PrintStats || Opts->ShouldSerializeStats) { - llvm::EnableStatistics(/* PrintOnExit= */ false); + llvm::EnableStatistics(/* DoPrintOnExit= */ false); } if (Opts->ShouldDisplayMacroExpansions) diff --git a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.h b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.h index d2016c3b112c..4db26028362f 100644 --- a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.h +++ b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.h @@ -29,10 +29,7 @@ namespace clang { class CompilerInstance; -class ASTUnit; -class ASTReader; class NamedDecl; -class Module; namespace ento { class ModelInjector : public CodeInjector { diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp index acceec690c11..80a70252721d 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp @@ -16,10 +16,10 @@ using namespace clang; using namespace tooling; using namespace dependencies; -llvm::ErrorOr<llvm::vfs::Status> -CachedFileSystemEntry::initFile(StringRef Filename, llvm::vfs::FileSystem &FS) { +llvm::ErrorOr<DependencyScanningWorkerFilesystem::TentativeEntry> +DependencyScanningWorkerFilesystem::readFile(StringRef Filename) { // Load the file and its content from the file system. - auto MaybeFile = FS.openFileForRead(Filename); + auto MaybeFile = getUnderlyingFS().openFileForRead(Filename); if (!MaybeFile) return MaybeFile.getError(); auto File = std::move(*MaybeFile); @@ -34,24 +34,43 @@ CachedFileSystemEntry::initFile(StringRef Filename, llvm::vfs::FileSystem &FS) { return MaybeBuffer.getError(); auto Buffer = std::move(*MaybeBuffer); - OriginalContents = std::move(Buffer); - return Stat; + // If the file size changed between read and stat, pretend it didn't. + if (Stat.getSize() != Buffer->getBufferSize()) + Stat = llvm::vfs::Status::copyWithNewSize(Stat, Buffer->getBufferSize()); + + return TentativeEntry(Stat, std::move(Buffer)); } -void CachedFileSystemEntry::minimizeFile() { - assert(OriginalContents && "minimizing missing contents"); +EntryRef DependencyScanningWorkerFilesystem::minimizeIfNecessary( + const CachedFileSystemEntry &Entry, StringRef Filename, bool Disable) { + if (Entry.isError() || Entry.isDirectory() || Disable || + !shouldMinimize(Filename, Entry.getUniqueID())) + return EntryRef(/*Minimized=*/false, Filename, Entry); + + CachedFileContents *Contents = Entry.getContents(); + assert(Contents && "contents not initialized"); + + // Double-checked locking. + if (Contents->MinimizedAccess.load()) + return EntryRef(/*Minimized=*/true, Filename, Entry); + + std::lock_guard<std::mutex> GuardLock(Contents->ValueLock); + + // Double-checked locking. + if (Contents->MinimizedAccess.load()) + return EntryRef(/*Minimized=*/true, Filename, Entry); llvm::SmallString<1024> MinimizedFileContents; // Minimize the file down to directives that might affect the dependencies. SmallVector<minimize_source_to_dependency_directives::Token, 64> Tokens; - if (minimizeSourceToDependencyDirectives(OriginalContents->getBuffer(), + if (minimizeSourceToDependencyDirectives(Contents->Original->getBuffer(), MinimizedFileContents, Tokens)) { // FIXME: Propagate the diagnostic if desired by the client. // Use the original file if the minimization failed. - MinimizedContentsStorage = - llvm::MemoryBuffer::getMemBuffer(*OriginalContents); - MinimizedContentsAccess.store(MinimizedContentsStorage.get()); - return; + Contents->MinimizedStorage = + llvm::MemoryBuffer::getMemBuffer(*Contents->Original); + Contents->MinimizedAccess.store(Contents->MinimizedStorage.get()); + return EntryRef(/*Minimized=*/true, Filename, Entry); } // The contents produced by the minimizer must be null terminated. @@ -74,16 +93,17 @@ void CachedFileSystemEntry::minimizeFile() { } Mapping[Range.Offset] = Range.Length; } - PPSkippedRangeMapping = std::move(Mapping); + Contents->PPSkippedRangeMapping = std::move(Mapping); - MinimizedContentsStorage = std::make_unique<llvm::SmallVectorMemoryBuffer>( + Contents->MinimizedStorage = std::make_unique<llvm::SmallVectorMemoryBuffer>( std::move(MinimizedFileContents)); - // The algorithm in `getOrCreateFileSystemEntry` uses the presence of - // minimized contents to decide whether an entry is up-to-date or not. - // If it is up-to-date, the skipped range mappings must be already computed. - // This is why we need to store the minimized contents **after** storing the - // skipped range mappings. Failing to do so would lead to a data race. - MinimizedContentsAccess.store(MinimizedContentsStorage.get()); + // This function performed double-checked locking using `MinimizedAccess`. + // Assigning it must be the last thing this function does. If we were to + // assign it before `PPSkippedRangeMapping`, other threads may skip the + // critical section (`MinimizedAccess != nullptr`) and access the mappings + // that are about to be initialized, leading to a data race. + Contents->MinimizedAccess.store(Contents->MinimizedStorage.get()); + return EntryRef(/*Minimized=*/true, Filename, Entry); } DependencyScanningFilesystemSharedCache:: @@ -98,12 +118,70 @@ DependencyScanningFilesystemSharedCache:: CacheShards = std::make_unique<CacheShard[]>(NumShards); } -DependencyScanningFilesystemSharedCache::SharedFileSystemEntry & -DependencyScanningFilesystemSharedCache::get(StringRef Key) { - CacheShard &Shard = CacheShards[llvm::hash_value(Key) % NumShards]; - std::lock_guard<std::mutex> LockGuard(Shard.CacheLock); - auto It = Shard.Cache.try_emplace(Key); - return It.first->getValue(); +DependencyScanningFilesystemSharedCache::CacheShard & +DependencyScanningFilesystemSharedCache::getShardForFilename( + StringRef Filename) const { + return CacheShards[llvm::hash_value(Filename) % NumShards]; +} + +DependencyScanningFilesystemSharedCache::CacheShard & +DependencyScanningFilesystemSharedCache::getShardForUID( + llvm::sys::fs::UniqueID UID) const { + auto Hash = llvm::hash_combine(UID.getDevice(), UID.getFile()); + return CacheShards[Hash % NumShards]; +} + +const CachedFileSystemEntry * +DependencyScanningFilesystemSharedCache::CacheShard::findEntryByFilename( + StringRef Filename) const { + std::lock_guard<std::mutex> LockGuard(CacheLock); + auto It = EntriesByFilename.find(Filename); + return It == EntriesByFilename.end() ? nullptr : It->getValue(); +} + +const CachedFileSystemEntry * +DependencyScanningFilesystemSharedCache::CacheShard::findEntryByUID( + llvm::sys::fs::UniqueID UID) const { + std::lock_guard<std::mutex> LockGuard(CacheLock); + auto It = EntriesByUID.find(UID); + return It == EntriesByUID.end() ? nullptr : It->getSecond(); +} + +const CachedFileSystemEntry & +DependencyScanningFilesystemSharedCache::CacheShard:: + getOrEmplaceEntryForFilename(StringRef Filename, + llvm::ErrorOr<llvm::vfs::Status> Stat) { + std::lock_guard<std::mutex> LockGuard(CacheLock); + auto Insertion = EntriesByFilename.insert({Filename, nullptr}); + if (Insertion.second) + Insertion.first->second = + new (EntryStorage.Allocate()) CachedFileSystemEntry(std::move(Stat)); + return *Insertion.first->second; +} + +const CachedFileSystemEntry & +DependencyScanningFilesystemSharedCache::CacheShard::getOrEmplaceEntryForUID( + llvm::sys::fs::UniqueID UID, llvm::vfs::Status Stat, + std::unique_ptr<llvm::MemoryBuffer> Contents) { + std::lock_guard<std::mutex> LockGuard(CacheLock); + auto Insertion = EntriesByUID.insert({UID, nullptr}); + if (Insertion.second) { + CachedFileContents *StoredContents = nullptr; + if (Contents) + StoredContents = new (ContentsStorage.Allocate()) + CachedFileContents(std::move(Contents)); + Insertion.first->second = new (EntryStorage.Allocate()) + CachedFileSystemEntry(std::move(Stat), StoredContents); + } + return *Insertion.first->second; +} + +const CachedFileSystemEntry & +DependencyScanningFilesystemSharedCache::CacheShard:: + getOrInsertEntryForFilename(StringRef Filename, + const CachedFileSystemEntry &Entry) { + std::lock_guard<std::mutex> LockGuard(CacheLock); + return *EntriesByFilename.insert({Filename, &Entry}).first->getValue(); } /// Whitelist file extensions that should be minimized, treating no extension as @@ -133,68 +211,79 @@ static bool shouldCacheStatFailures(StringRef Filename) { } void DependencyScanningWorkerFilesystem::disableMinimization( - StringRef RawFilename) { - llvm::SmallString<256> Filename; - llvm::sys::path::native(RawFilename, Filename); - NotToBeMinimized.insert(Filename); + StringRef Filename) { + // Since we're not done setting up `NotToBeMinimized` yet, we need to disable + // minimization explicitly. + if (llvm::ErrorOr<EntryRef> Result = + getOrCreateFileSystemEntry(Filename, /*DisableMinimization=*/true)) + NotToBeMinimized.insert(Result->getStatus().getUniqueID()); } -bool DependencyScanningWorkerFilesystem::shouldMinimize(StringRef RawFilename) { - if (!shouldMinimizeBasedOnExtension(RawFilename)) - return false; - - llvm::SmallString<256> Filename; - llvm::sys::path::native(RawFilename, Filename); - return !NotToBeMinimized.contains(Filename); +bool DependencyScanningWorkerFilesystem::shouldMinimize( + StringRef Filename, llvm::sys::fs::UniqueID UID) { + return shouldMinimizeBasedOnExtension(Filename) && + !NotToBeMinimized.contains(UID); } -void CachedFileSystemEntry::init(llvm::ErrorOr<llvm::vfs::Status> &&MaybeStatus, - StringRef Filename, - llvm::vfs::FileSystem &FS) { - if (!MaybeStatus || MaybeStatus->isDirectory()) - MaybeStat = std::move(MaybeStatus); - else - MaybeStat = initFile(Filename, FS); +const CachedFileSystemEntry & +DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForUID( + TentativeEntry TEntry) { + auto &Shard = SharedCache.getShardForUID(TEntry.Status.getUniqueID()); + return Shard.getOrEmplaceEntryForUID(TEntry.Status.getUniqueID(), + std::move(TEntry.Status), + std::move(TEntry.Contents)); } -llvm::ErrorOr<EntryRef> -DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry( +const CachedFileSystemEntry * +DependencyScanningWorkerFilesystem::findEntryByFilenameWithWriteThrough( StringRef Filename) { - bool ShouldBeMinimized = shouldMinimize(Filename); + if (const auto *Entry = LocalCache.findEntryByFilename(Filename)) + return Entry; + auto &Shard = SharedCache.getShardForFilename(Filename); + if (const auto *Entry = Shard.findEntryByFilename(Filename)) + return &LocalCache.insertEntryForFilename(Filename, *Entry); + return nullptr; +} - const auto *Entry = LocalCache.getCachedEntry(Filename); - if (Entry && !Entry->needsUpdate(ShouldBeMinimized)) - return EntryRef(ShouldBeMinimized, *Entry); +llvm::ErrorOr<const CachedFileSystemEntry &> +DependencyScanningWorkerFilesystem::computeAndStoreResult(StringRef Filename) { + llvm::ErrorOr<llvm::vfs::Status> Stat = getUnderlyingFS().status(Filename); + if (!Stat) { + if (!shouldCacheStatFailures(Filename)) + return Stat.getError(); + const auto &Entry = + getOrEmplaceSharedEntryForFilename(Filename, Stat.getError()); + return insertLocalEntryForFilename(Filename, Entry); + } - // FIXME: Handle PCM/PCH files. - // FIXME: Handle module map files. + if (const auto *Entry = findSharedEntryByUID(*Stat)) + return insertLocalEntryForFilename(Filename, *Entry); - auto &SharedCacheEntry = SharedCache.get(Filename); - { - std::lock_guard<std::mutex> LockGuard(SharedCacheEntry.ValueLock); - CachedFileSystemEntry &CacheEntry = SharedCacheEntry.Value; + auto TEntry = + Stat->isDirectory() ? TentativeEntry(*Stat) : readFile(Filename); - if (!CacheEntry.isInitialized()) { - auto MaybeStatus = getUnderlyingFS().status(Filename); - if (!MaybeStatus && !shouldCacheStatFailures(Filename)) - // HACK: We need to always restat non source files if the stat fails. - // This is because Clang first looks up the module cache and module - // files before building them, and then looks for them again. If we - // cache the stat failure, it won't see them the second time. - return MaybeStatus.getError(); - CacheEntry.init(std::move(MaybeStatus), Filename, getUnderlyingFS()); + const CachedFileSystemEntry *SharedEntry = [&]() { + if (TEntry) { + const auto &UIDEntry = getOrEmplaceSharedEntryForUID(std::move(*TEntry)); + return &getOrInsertSharedEntryForFilename(Filename, UIDEntry); } + return &getOrEmplaceSharedEntryForFilename(Filename, TEntry.getError()); + }(); - // Checking `needsUpdate` verifies the entry represents an opened file. - // Only checking `needsMinimization` could lead to minimization of files - // that we failed to load (such files don't have `OriginalContents`). - if (CacheEntry.needsUpdate(ShouldBeMinimized)) - CacheEntry.minimizeFile(); - } + return insertLocalEntryForFilename(Filename, *SharedEntry); +} - // Store the result in the local cache. - Entry = &SharedCacheEntry.Value; - return EntryRef(ShouldBeMinimized, *Entry); +llvm::ErrorOr<EntryRef> +DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry( + StringRef Filename, bool DisableMinimization) { + if (const auto *Entry = findEntryByFilenameWithWriteThrough(Filename)) + return minimizeIfNecessary(*Entry, Filename, DisableMinimization) + .unwrapError(); + auto MaybeEntry = computeAndStoreResult(Filename); + if (!MaybeEntry) + return MaybeEntry.getError(); + return minimizeIfNecessary(*MaybeEntry, Filename, DisableMinimization) + .unwrapError(); } llvm::ErrorOr<llvm::vfs::Status> @@ -241,16 +330,16 @@ private: llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> MinimizedVFSFile::create( EntryRef Entry, ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings) { + assert(!Entry.isError() && "error"); + if (Entry.isDirectory()) return std::make_error_code(std::errc::is_a_directory); - llvm::ErrorOr<StringRef> Contents = Entry.getContents(); - if (!Contents) - return Contents.getError(); auto Result = std::make_unique<MinimizedVFSFile>( - llvm::MemoryBuffer::getMemBuffer(*Contents, Entry.getName(), + llvm::MemoryBuffer::getMemBuffer(Entry.getContents(), + Entry.getStatus().getName(), /*RequiresNullTerminator=*/false), - *Entry.getStatus()); + Entry.getStatus()); const auto *EntrySkipMappings = Entry.getPPSkippedRangeMapping(); if (EntrySkipMappings && !EntrySkipMappings->empty() && PPSkipMappings) diff --git a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp index 29787b8a8894..75d0d50d851f 100644 --- a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp +++ b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp @@ -61,7 +61,7 @@ private: continue; llvm::BumpPtrAllocator Alloc; llvm::StringSaver Saver(Alloc); - llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, + llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, false, llvm::StringRef(Cmd.Directory), *FS); // Don't assign directly, Argv aliases CommandLine. std::vector<std::string> ExpandedArgv(Argv.begin(), Argv.end()); diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp index c1e25c41f719..51e8439b6b79 100644 --- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp +++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp @@ -243,8 +243,7 @@ struct TransferableCommand { llvm::Twine(ClangCLMode ? "/std:" : "-std=") + LangStandard::getLangStandardForKind(Std).getName()).str()); } - if (Filename.startswith("-") || (ClangCLMode && Filename.startswith("/"))) - Result.CommandLine.push_back("--"); + Result.CommandLine.push_back("--"); Result.CommandLine.push_back(std::string(Filename)); return Result; } diff --git a/clang/lib/Tooling/Syntax/Tree.cpp b/clang/lib/Tooling/Syntax/Tree.cpp index c813865e95cd..981bac508f73 100644 --- a/clang/lib/Tooling/Syntax/Tree.cpp +++ b/clang/lib/Tooling/Syntax/Tree.cpp @@ -9,6 +9,7 @@ #include "clang/Basic/TokenKinds.h" #include "clang/Tooling/Syntax/Nodes.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" #include <cassert> @@ -202,7 +203,7 @@ static void dumpLeaf(raw_ostream &OS, const syntax::Leaf *L, } static void dumpNode(raw_ostream &OS, const syntax::Node *N, - const SourceManager &SM, std::vector<bool> IndentMask) { + const SourceManager &SM, llvm::BitVector IndentMask) { auto DumpExtraInfo = [&OS](const syntax::Node *N) { if (N->getRole() != syntax::NodeRole::Unknown) OS << " " << N->getRole(); @@ -228,8 +229,8 @@ static void dumpNode(raw_ostream &OS, const syntax::Node *N, OS << "\n"; for (const syntax::Node &It : T->getChildren()) { - for (bool Filled : IndentMask) { - if (Filled) + for (unsigned Idx = 0; Idx < IndentMask.size(); ++Idx) { + if (IndentMask[Idx]) OS << "| "; else OS << " "; diff --git a/clang/lib/Tooling/Transformer/Parsing.cpp b/clang/lib/Tooling/Transformer/Parsing.cpp index 242db2a16b43..4f41e2e90def 100644 --- a/clang/lib/Tooling/Transformer/Parsing.cpp +++ b/clang/lib/Tooling/Transformer/Parsing.cpp @@ -33,7 +33,6 @@ using namespace transformer; // much as possible with the AST Matchers parsing. namespace { -using llvm::Error; using llvm::Expected; template <typename... Ts> using RangeSelectorOp = RangeSelector (*)(Ts...); diff --git a/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp b/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp index a1c99b60216b..7496e968469c 100644 --- a/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp +++ b/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp @@ -10,6 +10,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Transformer/SourceCode.h" #include "llvm/ADT/Twine.h" #include <string> @@ -60,6 +62,16 @@ bool tooling::needParensAfterUnaryOperator(const Expr &E) { return false; } +bool tooling::isKnownPointerLikeType(QualType Ty, ASTContext &Context) { + using namespace ast_matchers; + const auto PointerLikeTy = type(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(cxxRecordDecl(hasAnyName( + "::std::unique_ptr", "::std::shared_ptr", "::std::weak_ptr", + "::std::optional", "::absl::optional", "::llvm::Optional", + "absl::StatusOr", "::llvm::Expected")))))); + return match(PointerLikeTy, Ty, Context).size() > 0; +} + llvm::Optional<std::string> tooling::buildParens(const Expr &E, const ASTContext &Context) { StringRef Text = getText(E, Context); @@ -114,8 +126,10 @@ llvm::Optional<std::string> tooling::buildAddressOf(const Expr &E, return ("&" + Text).str(); } -llvm::Optional<std::string> tooling::buildDot(const Expr &E, - const ASTContext &Context) { +// Append the appropriate access operation (syntactically) to `E`, assuming `E` +// is a non-pointer value. +static llvm::Optional<std::string> +buildAccessForValue(const Expr &E, const ASTContext &Context) { if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E)) if (Op->getOpcode() == UO_Deref) { // Strip leading '*', add following '->'. @@ -138,8 +152,10 @@ llvm::Optional<std::string> tooling::buildDot(const Expr &E, return (Text + ".").str(); } -llvm::Optional<std::string> tooling::buildArrow(const Expr &E, - const ASTContext &Context) { +// Append the appropriate access operation (syntactically) to `E`, assuming `E` +// is a pointer value. +static llvm::Optional<std::string> +buildAccessForPointer(const Expr &E, const ASTContext &Context) { if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E)) if (Op->getOpcode() == UO_AddrOf) { // Strip leading '&', add following '.'. @@ -160,3 +176,63 @@ llvm::Optional<std::string> tooling::buildArrow(const Expr &E, return ("(" + Text + ")->").str(); return (Text + "->").str(); } + +llvm::Optional<std::string> tooling::buildDot(const Expr &E, + const ASTContext &Context) { + return buildAccessForValue(E, Context); +} + +llvm::Optional<std::string> tooling::buildArrow(const Expr &E, + const ASTContext &Context) { + return buildAccessForPointer(E, Context); +} + +// If `E` is an overloaded-operator call of kind `K` on an object `O`, returns +// `O`. Otherwise, returns `nullptr`. +static const Expr *maybeGetOperatorObjectArg(const Expr &E, + OverloadedOperatorKind K) { + if (const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(&E)) { + if (OpCall->getOperator() == K && OpCall->getNumArgs() == 1) + return OpCall->getArg(0); + } + return nullptr; +} + +static bool treatLikePointer(QualType Ty, PLTClass C, ASTContext &Context) { + switch (C) { + case PLTClass::Value: + return false; + case PLTClass::Pointer: + return isKnownPointerLikeType(Ty, Context); + } + llvm_unreachable("Unknown PLTClass enum"); +} + +// FIXME: move over the other `maybe` functionality from Stencil. Should all be +// in one place. +llvm::Optional<std::string> tooling::buildAccess(const Expr &RawExpression, + ASTContext &Context, + PLTClass Classification) { + if (RawExpression.isImplicitCXXThis()) + // Return the empty string, because `None` signifies some sort of failure. + return std::string(); + + const Expr *E = RawExpression.IgnoreImplicitAsWritten(); + + if (E->getType()->isAnyPointerType() || + treatLikePointer(E->getType(), Classification, Context)) { + // Strip off operator-> calls. They can only occur inside an actual arrow + // member access, so we treat them as equivalent to an actual object + // expression. + if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Arrow)) + E = Obj; + return buildAccessForPointer(*E, Context); + } + + if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Star)) { + if (treatLikePointer(Obj->getType(), Classification, Context)) + return buildAccessForPointer(*Obj, Context); + }; + + return buildAccessForValue(*E, Context); +} diff --git a/clang/lib/Tooling/Transformer/Stencil.cpp b/clang/lib/Tooling/Transformer/Stencil.cpp index 8b20ef34c3ff..348d04dbaf4a 100644 --- a/clang/lib/Tooling/Transformer/Stencil.cpp +++ b/clang/lib/Tooling/Transformer/Stencil.cpp @@ -11,7 +11,6 @@ #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Expr.h" #include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/SourceLocation.h" #include "clang/Lex/Lexer.h" #include "clang/Tooling/Transformer/SourceCode.h" @@ -56,39 +55,6 @@ static Error printNode(StringRef Id, const MatchFinder::MatchResult &Match, return Error::success(); } -// FIXME: Consider memoizing this function using the `ASTContext`. -static bool isSmartPointerType(QualType Ty, ASTContext &Context) { - using namespace ::clang::ast_matchers; - - // Optimization: hard-code common smart-pointer types. This can/should be - // removed if we start caching the results of this function. - auto KnownSmartPointer = - cxxRecordDecl(hasAnyName("::std::unique_ptr", "::std::shared_ptr")); - const auto QuacksLikeASmartPointer = cxxRecordDecl( - hasMethod(cxxMethodDecl(hasOverloadedOperatorName("->"), - returns(qualType(pointsTo(type()))))), - hasMethod(cxxMethodDecl(hasOverloadedOperatorName("*"), - returns(qualType(references(type())))))); - const auto SmartPointer = qualType(hasDeclaration( - cxxRecordDecl(anyOf(KnownSmartPointer, QuacksLikeASmartPointer)))); - return match(SmartPointer, Ty, Context).size() > 0; -} - -// Identifies use of `operator*` on smart pointers, and returns the underlying -// smart-pointer expression; otherwise, returns null. -static const Expr *isSmartDereference(const Expr &E, ASTContext &Context) { - using namespace ::clang::ast_matchers; - - const auto HasOverloadedArrow = cxxRecordDecl(hasMethod(cxxMethodDecl( - hasOverloadedOperatorName("->"), returns(qualType(pointsTo(type())))))); - // Verify it is a smart pointer by finding `operator->` in the class - // declaration. - auto Deref = cxxOperatorCallExpr( - hasOverloadedOperatorName("*"), hasUnaryOperand(expr().bind("arg")), - callee(cxxMethodDecl(ofClass(HasOverloadedArrow)))); - return selectFirst<Expr>("arg", match(Deref, E, Context)); -} - namespace { // An arbitrary fragment of code within a stencil. class RawTextStencil : public StencilInterface { @@ -196,7 +162,7 @@ public: break; case UnaryNodeOperator::MaybeDeref: if (E->getType()->isAnyPointerType() || - isSmartPointerType(E->getType(), *Match.Context)) { + tooling::isKnownPointerLikeType(E->getType(), *Match.Context)) { // Strip off any operator->. This can only occur inside an actual arrow // member access, so we treat it as equivalent to an actual object // expression. @@ -216,7 +182,7 @@ public: break; case UnaryNodeOperator::MaybeAddressOf: if (E->getType()->isAnyPointerType() || - isSmartPointerType(E->getType(), *Match.Context)) { + tooling::isKnownPointerLikeType(E->getType(), *Match.Context)) { // Strip off any operator->. This can only occur inside an actual arrow // member access, so we treat it as equivalent to an actual object // expression. @@ -311,34 +277,12 @@ public: if (E == nullptr) return llvm::make_error<StringError>(errc::invalid_argument, "Id not bound: " + BaseId); - if (!E->isImplicitCXXThis()) { - llvm::Optional<std::string> S; - if (E->getType()->isAnyPointerType() || - isSmartPointerType(E->getType(), *Match.Context)) { - // Strip off any operator->. This can only occur inside an actual arrow - // member access, so we treat it as equivalent to an actual object - // expression. - if (const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(E)) { - if (OpCall->getOperator() == clang::OO_Arrow && - OpCall->getNumArgs() == 1) { - E = OpCall->getArg(0); - } - } - S = tooling::buildArrow(*E, *Match.Context); - } else if (const auto *Operand = isSmartDereference(*E, *Match.Context)) { - // `buildDot` already handles the built-in dereference operator, so we - // only need to catch overloaded `operator*`. - S = tooling::buildArrow(*Operand, *Match.Context); - } else { - S = tooling::buildDot(*E, *Match.Context); - } - if (S.hasValue()) - *Result += *S; - else - return llvm::make_error<StringError>( - errc::invalid_argument, - "Could not construct object text from ID: " + BaseId); - } + llvm::Optional<std::string> S = tooling::buildAccess(*E, *Match.Context); + if (!S.hasValue()) + return llvm::make_error<StringError>( + errc::invalid_argument, + "Could not construct object text from ID: " + BaseId); + *Result += *S; return Member->eval(Match, Result); } }; |
