aboutsummaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/docs/ReleaseNotes.rst7
-rw-r--r--clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h2
-rw-r--r--clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def1
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/include/clang/Basic/ObjCRuntime.h28
-rw-r--r--clang/lib/AST/ASTContext.cpp23
-rw-r--r--clang/lib/Analysis/UnsafeBufferUsage.cpp38
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp16
-rw-r--r--clang/lib/Sema/SemaChecking.cpp4
-rw-r--r--clang/lib/Sema/SemaDecl.cpp94
-rw-r--r--clang/lib/Sema/SemaInit.cpp8
-rw-r--r--clang/lib/Sema/TreeTransform.h71
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp7
-rw-r--r--clang/lib/Tooling/Tooling.cpp8
-rw-r--r--clang/test/Analysis/errno-stdlibraryfunctions.c30
-rw-r--r--clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp12
-rw-r--r--clang/test/CodeGenObjC/messages.m3
-rw-r--r--clang/test/Driver/gnustep-dispatch-method.m38
-rw-r--r--clang/test/SemaCXX/crash-GH76228.cpp28
-rw-r--r--clang/test/SemaCXX/paren-list-agg-init.cpp2
-rw-r--r--clang/test/SemaCXX/template-instantiation.cpp15
-rw-r--r--clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp131
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