diff options
Diffstat (limited to 'clang')
22 files changed, 424 insertions, 144 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0c8fec6..778ce0e0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -518,6 +518,7 @@ Improvements to Clang's diagnostics - Clang now diagnoses definitions of friend function specializations, e.g. ``friend void f<>(int) {}``. - Clang now diagnoses narrowing conversions involving const references. (`#63151: <https://github.com/llvm/llvm-project/issues/63151>`_). +- Clang now diagnoses unexpanded packs within the template argument lists of function template specializations. Improvements to Clang's time-trace @@ -856,6 +857,9 @@ Bug Fixes to AST Handling - Fixed a bug where RecursiveASTVisitor fails to visit the initializer of a bitfield. `Issue 64916 <https://github.com/llvm/llvm-project/issues/64916>`_ +- Fixed a bug where Template Instantiation failed to handle Lambda Expressions + with certain types of Attributes. + (`#76521 <https://github.com/llvm/llvm-project/issues/76521>`_) Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ @@ -1127,9 +1131,10 @@ Improvements ^^^^^^^^^^^^ - Improved the ``unix.StdCLibraryFunctions`` checker by modeling more - functions like ``send``, ``recv``, ``readlink``, ``fflush`` and + functions like ``send``, ``recv``, ``readlink``, ``fflush``, ``mkdtemp`` and ``errno`` behavior. (`52ac71f92d38 <https://github.com/llvm/llvm-project/commit/52ac71f92d38f75df5cb88e9c090ac5fd5a71548>`_, + `#76671 <https://github.com/llvm/llvm-project/pull/76671>`_, `#71373 <https://github.com/llvm/llvm-project/pull/71373>`_, `#76557 <https://github.com/llvm/llvm-project/pull/76557>`_, `#71392 <https://github.com/llvm/llvm-project/pull/71392>`_) diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h index 8a2d566..b28f2c6 100644 --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h @@ -66,7 +66,7 @@ public: /// Invoked when an unsafe operation over raw pointers is found. virtual void handleUnsafeOperation(const Stmt *Operation, - bool IsRelatedToDecl) = 0; + bool IsRelatedToDecl, ASTContext &Ctx) = 0; /// Invoked when a fix is suggested against a variable. This function groups /// all variables that must be fixed together (i.e their types must be changed diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def index 757ee45..c976616 100644 --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def @@ -30,6 +30,7 @@ WARNING_GADGET(Decrement) WARNING_GADGET(ArraySubscript) WARNING_GADGET(PointerArithmetic) WARNING_GADGET(UnsafeBufferUsageAttr) +WARNING_GADGET(DataInvocation) FIXABLE_GADGET(ULCArraySubscript) // `DRE[any]` in an Unspecified Lvalue Context FIXABLE_GADGET(DerefSimplePtrArithFixable) FIXABLE_GADGET(PointerDereference) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index aebb7d9..e54f969 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12064,7 +12064,7 @@ def warn_unsafe_buffer_variable : Warning< InGroup<UnsafeBufferUsage>, DefaultIgnore; def warn_unsafe_buffer_operation : Warning< "%select{unsafe pointer operation|unsafe pointer arithmetic|" - "unsafe buffer access|function introduces unsafe buffer manipulation}0">, + "unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of span::data}0">, InGroup<UnsafeBufferUsage>, DefaultIgnore; def note_unsafe_buffer_operation : Note< "used%select{| in pointer arithmetic| in buffer access}0 here">; diff --git a/clang/include/clang/Basic/ObjCRuntime.h b/clang/include/clang/Basic/ObjCRuntime.h index 500b246..f05debe 100644 --- a/clang/include/clang/Basic/ObjCRuntime.h +++ b/clang/include/clang/Basic/ObjCRuntime.h @@ -100,16 +100,24 @@ public: bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) { // The GNUstep runtime uses a newer dispatch method by default from // version 1.6 onwards - if (getKind() == GNUstep && getVersion() >= VersionTuple(1, 6)) { - if (Arch == llvm::Triple::arm || - Arch == llvm::Triple::x86 || - Arch == llvm::Triple::x86_64) - return false; - } - else if ((getKind() == MacOSX) && isNonFragile() && - (getVersion() >= VersionTuple(10, 0)) && - (getVersion() < VersionTuple(10, 6))) - return Arch != llvm::Triple::x86_64; + if (getKind() == GNUstep) { + switch (Arch) { + case llvm::Triple::arm: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return !(getVersion() >= VersionTuple(1, 6)); + case llvm::Triple::aarch64: + case llvm::Triple::mips64: + return !(getVersion() >= VersionTuple(1, 9)); + case llvm::Triple::riscv64: + return !(getVersion() >= VersionTuple(2, 2)); + default: + return true; + } + } else if ((getKind() == MacOSX) && isNonFragile() && + (getVersion() >= VersionTuple(10, 0)) && + (getVersion() < VersionTuple(10, 6))) + return Arch != llvm::Triple::x86_64; // Except for deployment target of 10.5 or less, // Mac runtimes use legacy dispatch everywhere now. return true; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 0395b3e..b60dcfa 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2748,21 +2748,20 @@ bool ASTContext::hasUniqueObjectRepresentations( QualType Ty, bool CheckIfTriviallyCopyable) const { // C++17 [meta.unary.prop]: // The predicate condition for a template specialization - // has_unique_object_representations<T> shall be - // satisfied if and only if: + // has_unique_object_representations<T> shall be satisfied if and only if: // (9.1) - T is trivially copyable, and // (9.2) - any two objects of type T with the same value have the same - // object representation, where two objects - // of array or non-union class type are considered to have the same value - // if their respective sequences of - // direct subobjects have the same values, and two objects of union type - // are considered to have the same - // value if they have the same active member and the corresponding members - // have the same value. + // object representation, where: + // - two objects of array or non-union class type are considered to have + // the same value if their respective sequences of direct subobjects + // have the same values, and + // - two objects of union type are considered to have the same value if + // they have the same active member and the corresponding members have + // the same value. // The set of scalar types for which this condition holds is - // implementation-defined. [ Note: If a type has padding - // bits, the condition does not hold; otherwise, the condition holds true - // for unsigned integral types. -- end note ] + // implementation-defined. [ Note: If a type has padding bits, the condition + // does not hold; otherwise, the condition holds true for unsigned integral + // types. -- end note ] assert(!Ty.isNull() && "Null QualType sent to unique object rep check"); // Arrays are unique only if their element type is unique. diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 70eec1c..724c430 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -721,6 +721,34 @@ public: DeclUseList getClaimedVarUseSites() const override { return {}; } }; +// Warning gadget for unsafe invocation of span::data method. +// Triggers when the pointer returned by the invocation is immediately +// cast to a larger type. + +class DataInvocationGadget : public WarningGadget { + constexpr static const char *const OpTag = "data_invocation_expr"; + const ExplicitCastExpr *Op; + +public: + DataInvocationGadget(const MatchFinder::MatchResult &Result) + : WarningGadget(Kind::DataInvocation), + Op(Result.Nodes.getNodeAs<ExplicitCastExpr>(OpTag)) {} + + static bool classof(const Gadget *G) { + return G->getKind() == Kind::DataInvocation; + } + + static Matcher matcher() { + return stmt( + explicitCastExpr(has(cxxMemberCallExpr(callee(cxxMethodDecl( + hasName("data"), ofClass(hasName("std::span"))))))) + .bind(OpTag)); + } + const Stmt *getBaseStmt() const override { return Op; } + + DeclUseList getClaimedVarUseSites() const override { return {}; } +}; + // Represents expressions of the form `DRE[*]` in the Unspecified Lvalue // Context (see `isInUnspecifiedLvalueContext`). // Note here `[]` is the built-in subscript operator. @@ -2657,8 +2685,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D, // every problematic operation and consider it done. No need to deal // with fixable gadgets, no need to group operations by variable. for (const auto &G : WarningGadgets) { - Handler.handleUnsafeOperation(G->getBaseStmt(), - /*IsRelatedToDecl=*/false); + Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false, + D->getASTContext()); } // This return guarantees that most of the machine doesn't run when @@ -2893,7 +2921,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D, Tracker, Handler, VarGrpMgr); for (const auto &G : UnsafeOps.noVar) { - Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false); + Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false, + D->getASTContext()); } for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar) { @@ -2904,7 +2933,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D, : FixItList{}, D); for (const auto &G : WarningGadgets) { - Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/true); + Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/true, + D->getASTContext()); } } } diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 0947e8b..9eb1df5 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2226,8 +2226,8 @@ public: UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions) : S(S), SuggestSuggestions(SuggestSuggestions) {} - void handleUnsafeOperation(const Stmt *Operation, - bool IsRelatedToDecl) override { + void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl, + ASTContext &Ctx) override { SourceLocation Loc; SourceRange Range; unsigned MsgParam = 0; @@ -2261,6 +2261,18 @@ public: // note_unsafe_buffer_operation doesn't have this mode yet. assert(!IsRelatedToDecl && "Not implemented yet!"); MsgParam = 3; + } else if (const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) { + QualType destType = ECE->getType(); + const uint64_t dSize = + Ctx.getTypeSize(destType.getTypePtr()->getPointeeType()); + if (const auto *CE = dyn_cast<CXXMemberCallExpr>(ECE->getSubExpr())) { + QualType srcType = CE->getType(); + const uint64_t sSize = + Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType()); + if (sSize >= dSize) + return; + } + MsgParam = 4; } Loc = Operation->getBeginLoc(); Range = Operation->getSourceRange(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index da0570b..3168d38 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -16677,7 +16677,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> { /// Have we issued a diagnostic for this object already? bool Diagnosed = false; - UsageInfo() = default; + UsageInfo(); }; using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>; @@ -17436,6 +17436,8 @@ public: } }; +SequenceChecker::UsageInfo::UsageInfo() = default; + } // namespace void Sema::CheckUnsequencedOperations(const Expr *E) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ffbe317..8e46c49 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9900,15 +9900,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. bool Invalid = false; + TemplateIdAnnotation *TemplateId = + D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId + ? D.getName().TemplateId + : nullptr; TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), - D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId - ? D.getName().TemplateId - : nullptr, - TemplateParamLists, isFriend, isMemberSpecialization, - Invalid); + D.getCXXScopeSpec(), TemplateId, TemplateParamLists, isFriend, + isMemberSpecialization, Invalid); if (TemplateParams) { // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) @@ -9921,6 +9921,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (Name.getNameKind() == DeclarationName::CXXDestructorName) { Diag(NewFD->getLocation(), diag::err_destructor_template); NewFD->setInvalidDecl(); + // Function template with explicit template arguments. + } else if (TemplateId) { + Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); + NewFD->setInvalidDecl(); } // If we're adding a template to a dependent context, we may need to @@ -9973,6 +9978,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << FixItHint::CreateRemoval(RemoveRange) << FixItHint::CreateInsertion(InsertLoc, "<>"); Invalid = true; + + // Recover by faking up an empty template argument list. + HasExplicitTemplateArgs = true; + TemplateArgs.setLAngleLoc(InsertLoc); + TemplateArgs.setRAngleLoc(InsertLoc); } } } else { @@ -9986,6 +9996,33 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (TemplateParamLists.size() > 0) // For source fidelity, store all the template param lists. NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); + + // "friend void foo<>(int);" is an implicit specialization decl. + if (isFriend && TemplateId) + isFunctionTemplateSpecialization = true; + } + + // If this is a function template specialization and the unqualified-id of + // the declarator-id is a template-id, convert the template argument list + // into our AST format and check for unexpanded packs. + if (isFunctionTemplateSpecialization && TemplateId) { + HasExplicitTemplateArgs = true; + + TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + + // FIXME: Should we check for unexpanded packs if this was an (invalid) + // declaration of a function template partial specialization? Should we + // consider the unexpanded pack context to be a partial specialization? + for (const TemplateArgumentLoc &ArgLoc : TemplateArgs.arguments()) { + if (DiagnoseUnexpandedParameterPack( + ArgLoc, isFriend ? UPPC_FriendDeclaration + : UPPC_ExplicitSpecialization)) + NewFD->setInvalidDecl(); + } } if (Invalid) { @@ -10438,46 +10475,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::ext_operator_new_delete_declared_inline) << NewFD->getDeclName(); - // If the declarator is a template-id, translate the parser's template - // argument list into our AST format. - if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getName().TemplateId; - TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); - TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - translateTemplateArguments(TemplateArgsPtr, - TemplateArgs); - - HasExplicitTemplateArgs = true; - - if (NewFD->isInvalidDecl()) { - HasExplicitTemplateArgs = false; - } else if (FunctionTemplate) { - // Function template with explicit template arguments. - Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) - << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); - - HasExplicitTemplateArgs = false; - } else if (isFriend) { - // "friend void foo<>(int);" is an implicit specialization decl. - isFunctionTemplateSpecialization = true; - } else { - assert(isFunctionTemplateSpecialization && - "should have a 'template<>' for this decl"); - } - } else if (isFriend && isFunctionTemplateSpecialization) { - // This combination is only possible in a recovery case; the user - // wrote something like: - // template <> friend void foo(int); - // which we're recovering from as if the user had written: - // friend void foo<>(int); - // Go ahead and fake up a template id. - HasExplicitTemplateArgs = true; - TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); - TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); - } - // We do not add HD attributes to specializations here because // they may have different constexpr-ness compared to their // templates and, after maybeAddCUDAHostDeviceAttrs() is applied, @@ -15845,8 +15842,6 @@ static void diagnoseImplicitlyRetainedSelf(Sema &S) { } void Sema::CheckCoroutineWrapper(FunctionDecl *FD) { - if (!FD) - return; RecordDecl *RD = FD->getReturnType()->getAsRecordDecl(); if (!RD || !RD->getUnderlyingDecl()->hasAttr<CoroReturnTypeAttr>()) return; @@ -15869,7 +15864,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - if (getLangOpts().Coroutines) { + // If we skip function body, we can't tell if a function is a coroutine. + if (getLangOpts().Coroutines && FD && !FD->hasSkippedBody()) { if (FSI->isCoroutine()) CheckCompletedCoroutineBody(FD, Body); else diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index cc9db5d..61d244f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -5512,14 +5512,6 @@ static void TryOrBuildParenListInitialization( } else if (auto *RT = Entity.getType()->getAs<RecordType>()) { bool IsUnion = RT->isUnionType(); const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->isInvalidDecl()) { - // Exit early to avoid confusion when processing members. - // We do the same for braced list initialization in - // `CheckStructUnionTypes`. - Sequence.SetFailed( - clang::InitializationSequence::FK_ParenthesizedListInitFailed); - return; - } if (!IsUnion) { for (const CXXBaseSpecifier &Base : RD->bases()) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 7df5bf0..5e9b518 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -674,6 +674,10 @@ public: Qualifiers ThisTypeQuals, Fn TransformExceptionSpec); + template <typename Fn> + QualType TransformAttributedType(TypeLocBuilder &TLB, AttributedTypeLoc TL, + Fn TransformModifiedType); + bool TransformExceptionSpec(SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, SmallVectorImpl<QualType> &Exceptions, @@ -7050,12 +7054,12 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, return Result; } -template<typename Derived> +template <typename Derived> +template <typename Fn> QualType TreeTransform<Derived>::TransformAttributedType( - TypeLocBuilder &TLB, - AttributedTypeLoc TL) { + TypeLocBuilder &TLB, AttributedTypeLoc TL, Fn TransformModifiedTypeFn) { const AttributedType *oldType = TL.getTypePtr(); - QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc()); + QualType modifiedType = TransformModifiedTypeFn(TLB, TL.getModifiedLoc()); if (modifiedType.isNull()) return QualType(); @@ -7100,6 +7104,15 @@ QualType TreeTransform<Derived>::TransformAttributedType( } template <typename Derived> +QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB, + AttributedTypeLoc TL) { + return getDerived().TransformAttributedType( + TLB, TL, [&](TypeLocBuilder &TLB, TypeLoc ModifiedLoc) -> QualType { + return getDerived().TransformType(TLB, ModifiedLoc); + }); +} + +template <typename Derived> QualType TreeTransform<Derived>::TransformBTFTagAttributedType( TypeLocBuilder &TLB, BTFTagAttributedTypeLoc TL) { // The BTFTagAttributedType is available for C only. @@ -13600,32 +13613,56 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // transformed parameters. TypeSourceInfo *NewCallOpTSI = nullptr; { - TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); - auto OldCallOpFPTL = - OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>(); + auto OldCallOpTypeLoc = + E->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + + auto TransformFunctionProtoTypeLoc = + [this](TypeLocBuilder &TLB, FunctionProtoTypeLoc FPTL) -> QualType { + SmallVector<QualType, 4> ExceptionStorage; + TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. + return this->TransformFunctionProtoType( + TLB, FPTL, nullptr, Qualifiers(), + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return This->TransformExceptionSpec(FPTL.getBeginLoc(), ESI, + ExceptionStorage, Changed); + }); + }; + QualType NewCallOpType; TypeLocBuilder NewCallOpTLBuilder; - SmallVector<QualType, 4> ExceptionStorage; - TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. - QualType NewCallOpType = TransformFunctionProtoType( - NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(), - [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { - return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, - ExceptionStorage, Changed); - }); + + if (auto ATL = OldCallOpTypeLoc.getAs<AttributedTypeLoc>()) { + NewCallOpType = this->TransformAttributedType( + NewCallOpTLBuilder, ATL, + [&](TypeLocBuilder &TLB, TypeLoc TL) -> QualType { + return TransformFunctionProtoTypeLoc( + TLB, TL.castAs<FunctionProtoTypeLoc>()); + }); + } else { + auto FPTL = OldCallOpTypeLoc.castAs<FunctionProtoTypeLoc>(); + NewCallOpType = TransformFunctionProtoTypeLoc(NewCallOpTLBuilder, FPTL); + } + if (NewCallOpType.isNull()) return ExprError(); NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); } + ArrayRef<ParmVarDecl *> Params; + if (auto ATL = NewCallOpTSI->getTypeLoc().getAs<AttributedTypeLoc>()) { + Params = ATL.getModifiedLoc().castAs<FunctionProtoTypeLoc>().getParams(); + } else { + auto FPTL = NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>(); + Params = FPTL.getParams(); + } + getSema().CompleteLambdaCallOperator( NewCallOperator, E->getCallOperator()->getLocation(), E->getCallOperator()->getInnerLocStart(), E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI, E->getCallOperator()->getConstexprKind(), - E->getCallOperator()->getStorageClass(), - NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(), + E->getCallOperator()->getStorageClass(), Params, E->hasExplicitResultType()); getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 6560fd2..2006865 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -2507,10 +2507,13 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( .ArgConstraint(NotNull(ArgNo(0)))); // char *mkdtemp(char *template); - // FIXME: Improve for errno modeling. addToFunctionSummaryMap( "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}), - Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); + Summary(NoEvalCall) + .Case({ReturnValueCondition(BO_EQ, ArgNo(0))}, + ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg) + .ArgConstraint(NotNull(ArgNo(0)))); // char *getcwd(char *buf, size_t size); // FIXME: Improve for errno modeling. diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index d192c7f..d82cd5e 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -554,6 +554,8 @@ int ClangTool::run(ToolAction *Action) { << CWD.getError().message() << "\n"; } + size_t NumOfTotalFiles = AbsolutePaths.size(); + unsigned ProcessedFileCounter = 0; for (llvm::StringRef File : AbsolutePaths) { // Currently implementations of CompilationDatabase::getCompileCommands can // change the state of the file system (e.g. prepare generated headers), so @@ -609,7 +611,11 @@ int ClangTool::run(ToolAction *Action) { // FIXME: We need a callback mechanism for the tool writer to output a // customized message for each file. - LLVM_DEBUG({ llvm::dbgs() << "Processing: " << File << ".\n"; }); + if (NumOfTotalFiles > 1) + llvm::errs() << "[" + std::to_string(++ProcessedFileCounter) + "/" + + std::to_string(NumOfTotalFiles) + + "] Processing file " + File + << ".\n"; ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(), PCHContainerOps); Invocation.setDiagnosticConsumer(DiagConsumer); diff --git a/clang/test/Analysis/errno-stdlibraryfunctions.c b/clang/test/Analysis/errno-stdlibraryfunctions.c index dafda76..80e14c4 100644 --- a/clang/test/Analysis/errno-stdlibraryfunctions.c +++ b/clang/test/Analysis/errno-stdlibraryfunctions.c @@ -7,12 +7,9 @@ // RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true #include "Inputs/errno_var.h" +#include "Inputs/std-c-library-functions-POSIX.h" -typedef typeof(sizeof(int)) size_t; -typedef __typeof(sizeof(int)) off_t; -typedef size_t ssize_t; -ssize_t send(int sockfd, const void *buf, size_t len, int flags); -off_t lseek(int fildes, off_t offset, int whence); +#define NULL ((void *) 0) void clang_analyzer_warnIfReached(); void clang_analyzer_eval(int); @@ -54,3 +51,26 @@ int errno_lseek(int fildes, off_t offset) { } return 0; } + +void errno_mkstemp(char *template) { + int FD = mkstemp(template); + if (FD >= 0) { + if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}} + close(FD); + } else { + clang_analyzer_eval(FD == -1); // expected-warning{{TRUE}} + clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}} + if (errno) {} // no warning + } +} + +void errno_mkdtemp(char *template) { + char *Dir = mkdtemp(template); + if (Dir == NULL) { + clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}} + if (errno) {} // no warning + } else { + clang_analyzer_eval(Dir == template); // expected-warning{{TRUE}} + if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}} + } +} diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index 30ce6b4..3c500c2 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -376,6 +376,11 @@ namespace Specializations { template<typename... Ts> struct PrimaryClass<Ts>; // expected-error{{partial specialization contains unexpanded parameter pack 'Ts'}} + template<typename T, typename... Ts> + void PrimaryFunction(); + template<typename T, typename... Ts> + void PrimaryFunction<Ts>(); // expected-error{{function template partial specialization is not allowed}} + #if __cplusplus >= 201402L template<typename T, typename... Ts> constexpr int PrimaryVar = 0; @@ -392,6 +397,13 @@ namespace Specializations { template<typename U> struct InnerClass<U, Ts>; // expected-error{{partial specialization contains unexpanded parameter pack 'Ts'}} + template<typename... Us> + void InnerFunction(); + template<> + void InnerFunction<Ts>(); // expected-error{{explicit specialization contains unexpanded parameter pack 'Ts'}} + + friend void PrimaryFunction<Ts>(); // expected-error{{friend declaration contains unexpanded parameter pack 'Ts'}} + #if __cplusplus >= 201402L template<typename... Us> constexpr static int InnerVar = 0; diff --git a/clang/test/CodeGenObjC/messages.m b/clang/test/CodeGenObjC/messages.m index f93d35a..41f9d2f 100644 --- a/clang/test/CodeGenObjC/messages.m +++ b/clang/test/CodeGenObjC/messages.m @@ -1,7 +1,8 @@ // RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-MAC // RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-MAC-NF // RUN: %clang_cc1 -fobjc-runtime=gcc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-GNU -// RUN: %clang_cc1 -fobjc-runtime=gnustep -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-GNU-NF +// RUN: %clang_cc1 -fobjc-runtime=gnustep -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-GNU-NF +// RUN: %clang_cc1 -fobjc-runtime=gnustep-2.2 -fobjc-dispatch-method=non-legacy -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-MAC typedef struct { int x; diff --git a/clang/test/Driver/gnustep-dispatch-method.m b/clang/test/Driver/gnustep-dispatch-method.m new file mode 100644 index 0000000..6cd043f --- /dev/null +++ b/clang/test/Driver/gnustep-dispatch-method.m @@ -0,0 +1,38 @@ +// DEFINE: %{triple} = +// DEFINE: %{ver} = 1.6 +// DEFINE: %{prefix} = CHECK-MSGSEND +// DEFINE: %{check} = %clang --target=%{triple} -fobjc-runtime=gnustep-%{ver} -### -c %s 2>&1 | FileCheck -check-prefix=%{prefix} %s + +// REDEFINE: %{ver} = 1.6 +// REDEFINE: %{triple} = i386-unknown-freebsd +// RUN: %{check} +// REDEFINE: %{triple} = x86_64-unknown-freebsd +// RUN: %{check} +// REDEFINE: %{triple} = arm-unknown-freebsd +// RUN: %{check} +// REDEFINE: %{prefix} = CHECK-MSGLOOKUP +// REDEFINE: %{triple} = aarch64-unknown-freebsd +// RUN: %{check} +// REDEFINE: %{triple} = mips64-unknown-freebsd +// RUN: %{check} +// REDEFINE: %{triple} = riscv64-unknown-freebsd +// RUN: %{check} + +// REDEFINE: %{ver} = 1.9 +// REDEFINE: %{prefix} = CHECK-MSGSEND +// REDEFINE: %{triple} = aarch64-unknown-freebsd +// RUN: %{check} +// REDEFINE: %{triple} = mips64-unknown-freebsd +// RUN: %{check} +// REDEFINE: %{prefix} = CHECK-MSGLOOKUP +// REDEFINE: %{triple} = riscv64-unknown-freebsd +// RUN: %{check} + +// REDEFINE: %{ver} = 2.2 +// REDEFINE: %{prefix} = CHECK-MSGSEND +// REDEFINE: %{triple} = riscv64-unknown-freebsd +// RUN: %{check} + + +// CHECK-MSGSEND: "-cc1"{{.*}} "-fobjc-dispatch-method=non-legacy" +// CHECK-MSGLOOKUP-NOT: "-cc1"{{.*}} "-fobjc-dispatch-method=non-legacy" diff --git a/clang/test/SemaCXX/crash-GH76228.cpp b/clang/test/SemaCXX/crash-GH76228.cpp deleted file mode 100644 index 33a9395..0000000 --- a/clang/test/SemaCXX/crash-GH76228.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %clang_cc1 -std=c++20 -verify %s -// Check we don't crash on incomplete members and bases when handling parenthesized initialization. -class incomplete; // expected-note@-0 3 {{forward declaration of 'incomplete'}} -struct foo { - int a; - incomplete b; - // expected-error@-1 {{incomplete type}} -}; -foo a1(0); - -struct one_int { - int a; -}; -struct bar : one_int, incomplete {}; -// expected-error@-1 {{incomplete type}} -bar a2(0); - -incomplete a3[3](1,2,3); -// expected-error@-1 {{incomplete type}} - -struct qux : foo { -}; -qux a4(0); - -struct fred { - foo a[3]; -}; -fred a5(0); diff --git a/clang/test/SemaCXX/paren-list-agg-init.cpp b/clang/test/SemaCXX/paren-list-agg-init.cpp index c1964a5..f60b20e 100644 --- a/clang/test/SemaCXX/paren-list-agg-init.cpp +++ b/clang/test/SemaCXX/paren-list-agg-init.cpp @@ -289,7 +289,7 @@ int test() { // used to crash S a(0, 1); S b(0); - S c(0, 0, 1); + S c(0, 0, 1); // beforecxx20-warning {{aggregate initialization of type 'S' from a parenthesized list of values is a C++20 extension}} S d {0, 1}; S e {0}; diff --git a/clang/test/SemaCXX/template-instantiation.cpp b/clang/test/SemaCXX/template-instantiation.cpp new file mode 100644 index 0000000..8543af0 --- /dev/null +++ b/clang/test/SemaCXX/template-instantiation.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -verify -fsyntax-only %s +// expected-no-diagnostics + +namespace GH76521 { + +template <typename T> +void foo() { + auto l = []() __attribute__((preserve_most)) {}; +} + +void bar() { + foo<int>(); +} + +} diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp new file mode 100644 index 0000000..79eb3bb --- /dev/null +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp @@ -0,0 +1,131 @@ +// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fblocks -include %s -verify %s + +// RUN: %clang -x c++ -frtti -fsyntax-only -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s +// RUN: %clang_cc1 -std=c++11 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s +// RUN: %clang_cc1 -std=c++20 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s +// CHECK-NOT: [-Wunsafe-buffer-usage] + +#ifndef INCLUDED +#define INCLUDED +#pragma clang system_header + +// no spanification warnings for system headers +#else + +namespace std { + class type_info; + class bad_cast; + class bad_typeid; +} +using size_t = __typeof(sizeof(int)); +void *malloc(size_t); + +void foo(int v) { +} + +void foo(int *p){} + +namespace std{ + template <typename T> class span { + + T *elements; + + span(T *, unsigned){} + + public: + + constexpr span<T> subspan(size_t offset, size_t count) const { + return span<T> (elements+offset, count); // expected-warning{{unsafe pointer arithmetic}} + } + + constexpr T* data() const noexcept { + return elements; + } + + + constexpr T* hello() const noexcept { + return elements; + } +}; + + template <typename T> class span_duplicate { + span_duplicate(T *, unsigned){} + + T array[10]; + + public: + + T* data() { + return array; + } + +}; +} + +using namespace std; + +class A { + int a, b, c; +}; + +class B { + int a, b, c; +}; + +struct Base { + virtual ~Base() = default; +}; + +struct Derived: Base { + int d; +}; + +void cast_without_data(int *ptr) { + A *a = (A*) ptr; + float *p = (float*) ptr; +} + +void warned_patterns(std::span<int> span_ptr, std::span<Base> base_span, span<int> span_without_qual) { + A *a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}} + a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}} + + A *a2 = (A*) span_without_qual.data(); // expected-warning{{unsafe invocation of span::data}} + + // TODO:: Should we warn when we cast from base to derived type? + Derived *b = dynamic_cast<Derived*> (base_span.data());// expected-warning{{unsafe invocation of span::data}} + + // TODO:: This pattern is safe. We can add special handling for it, if we decide this + // is the recommended fixit for the unsafe invocations. + A *a3 = (A*)span_ptr.subspan(0, sizeof(A)).data(); // expected-warning{{unsafe invocation of span::data}} +} + +void not_warned_patterns(std::span<A> span_ptr, std::span<Base> base_span) { + int *p = (int*) span_ptr.data(); // Cast to a smaller type + + B *b = (B*) span_ptr.data(); // Cast to a type of same size. + + p = (int*) span_ptr.data(); + A *a = (A*) span_ptr.hello(); // Invoking other methods. +} + +// We do not want to warn about other types +void other_classes(std::span_duplicate<int> span_ptr) { + int *p; + A *a = (A*)span_ptr.data(); + a = (A*)span_ptr.data(); +} + +// Potential source for false negatives + +A false_negatives(std::span<int> span_pt, span<A> span_A) { + int *ptr = span_pt.data(); + + A *a1 = (A*)ptr; //TODO: We want to warn here eventually. + + A *a2= span_A.data(); + return *a2; // TODO: Can cause OOB if span_pt is empty + +} +#endif |