Commit a59e21d4 authored by Joel E. Denny's avatar Joel E. Denny
Browse files

Merge branch 'clacc-ci-main' into Clacc

This merge brings in one conflicting commit from upstream,
f2f88f3e, which disables out-of-tree libomptarget builds.  This
merge makes related adjustments to Clacc's cmake code that installs
OpenMP libraries to Clang's lib directory.

This merge also brings in CI config xfail updates due to upstream
changes.
parents 6f8a96d6 9a6b3c87
......@@ -73,6 +73,11 @@ stages:
PATH_PREPEND:
/opt/nvidia/hpc_sdk/Linux_ppc64le/21.2/cuda/11.0/bin
LIT_NTHREADS_DIVISOR: 4
# This leaves the following failure for leconte as the XFAIL is specified in
# the test from upstream:
#
# Unexpectedly Passed Tests (1):
# libomptarget :: nvptx64-nvidia-cuda :: unified_shared_memory/api.c
XFAIL:
"libomp :: affinity/kmp-hw-subset.c"
......@@ -108,6 +113,8 @@ stages:
CodeGen/AMDGPU/GlobalISel/irtranslator-call-sret.ll
CodeGen/AMDGPU/GlobalISel/irtranslator-call.ll
CodeGen/AMDGPU/GlobalISel/irtranslator-indirect-call.ll
CodeGen/AMDGPU/GlobalISel/irtranslator-sibling-call.ll
CodeGen/AMDGPU/GlobalISel/irtranslator-tail-call.ll
CodeGen/AMDGPU/call-constant.ll
CodeGen/AMDGPU/indirect-call.ll
CodeGen/AMDGPU/returnaddress.ll
......
......@@ -229,7 +229,7 @@ Welcome to the LLVM project!
The LLVM project has multiple components. The core of the project is
itself called "LLVM". This contains all of the tools, libraries, and header
files needed to process intermediate representations and converts it into
files needed to process intermediate representations and convert them into
object files. Tools include an assembler, disassembler, bitcode analyzer, and
bitcode optimizer. It also contains basic regression tests.
......
# Reporting LLVM Security Issues
To report security issues in LLVM, please follow the steps outlined on the
[LLVM Security Group](https://llvm.org/docs/Security.html#how-to-report-a-security-issue)
page.
......@@ -446,6 +446,9 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
case DiagnosticsEngine::Warning:
CheckName = "clang-diagnostic-warning";
break;
case DiagnosticsEngine::Remark:
CheckName = "clang-diagnostic-remark";
break;
default:
CheckName = "clang-diagnostic-unknown";
break;
......@@ -460,7 +463,10 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
Level = ClangTidyError::Error;
LastErrorRelatesToUserCode = true;
LastErrorPassesLineFilter = true;
} else if (DiagLevel == DiagnosticsEngine::Remark) {
Level = ClangTidyError::Remark;
}
bool IsWarningAsError = DiagLevel == DiagnosticsEngine::Warning &&
Context.treatAsError(CheckName);
Errors.emplace_back(CheckName, Level, Context.getCurrentBuildDirectory(),
......
......@@ -9,6 +9,7 @@
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "IdDependentBackwardBranchCheck.h"
#include "KernelNameRestrictionCheck.h"
#include "SingleWorkItemBarrierCheck.h"
#include "StructPackAlignCheck.h"
......@@ -23,6 +24,8 @@ namespace altera {
class AlteraModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<IdDependentBackwardBranchCheck>(
"altera-id-dependent-backward-branch");
CheckFactories.registerCheck<KernelNameRestrictionCheck>(
"altera-kernel-name-restriction");
CheckFactories.registerCheck<SingleWorkItemBarrierCheck>(
......
......@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangTidyAlteraModule
AlteraTidyModule.cpp
IdDependentBackwardBranchCheck.cpp
KernelNameRestrictionCheck.cpp
SingleWorkItemBarrierCheck.cpp
StructPackAlignCheck.cpp
......
//===--- IdDependentBackwardBranchCheck.cpp - clang-tidy ------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "IdDependentBackwardBranchCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace altera {
void IdDependentBackwardBranchCheck::registerMatchers(MatchFinder *Finder) {
// Prototype to identify all variables which hold a thread-variant ID.
// First Matcher just finds all the direct assignments of either ID call.
const auto ThreadID = expr(hasDescendant(callExpr(callee(functionDecl(
anyOf(hasName("get_global_id"), hasName("get_local_id")))))));
const auto RefVarOrField = forEachDescendant(
stmt(anyOf(declRefExpr(to(varDecl())).bind("assign_ref_var"),
memberExpr(member(fieldDecl())).bind("assign_ref_field"))));
Finder->addMatcher(
compoundStmt(
// Bind on actual get_local/global_id calls.
forEachDescendant(
stmt(
anyOf(declStmt(hasDescendant(varDecl(hasInitializer(ThreadID))
.bind("tid_dep_var"))),
binaryOperator(allOf(
isAssignmentOperator(), hasRHS(ThreadID),
hasLHS(anyOf(
declRefExpr(to(varDecl().bind("tid_dep_var"))),
memberExpr(member(
fieldDecl().bind("tid_dep_field")))))))))
.bind("straight_assignment"))),
this);
// Bind all VarDecls that include an initializer with a variable DeclRefExpr
// (in case it is ID-dependent).
Finder->addMatcher(
stmt(forEachDescendant(
varDecl(hasInitializer(RefVarOrField)).bind("pot_tid_var"))),
this);
// Bind all VarDecls that are assigned a value with a variable DeclRefExpr (in
// case it is ID-dependent).
Finder->addMatcher(
stmt(forEachDescendant(binaryOperator(
allOf(isAssignmentOperator(), hasRHS(RefVarOrField),
hasLHS(anyOf(
declRefExpr(to(varDecl().bind("pot_tid_var"))),
memberExpr(member(fieldDecl().bind("pot_tid_field"))))))))),
this);
// Second Matcher looks for branch statements inside of loops and bind on the
// condition expression IF it either calls an ID function or has a variable
// DeclRefExpr. DeclRefExprs are checked later to confirm whether the variable
// is ID-dependent.
const auto CondExpr =
expr(anyOf(hasDescendant(callExpr(callee(functionDecl(
anyOf(hasName("get_global_id"),
hasName("get_local_id")))))
.bind("id_call")),
hasDescendant(stmt(anyOf(declRefExpr(to(varDecl())),
memberExpr(member(fieldDecl())))))))
.bind("cond_expr");
Finder->addMatcher(stmt(anyOf(forStmt(hasCondition(CondExpr)),
doStmt(hasCondition(CondExpr)),
whileStmt(hasCondition(CondExpr))))
.bind("backward_branch"),
this);
}
IdDependentBackwardBranchCheck::IdDependencyRecord *
IdDependentBackwardBranchCheck::hasIdDepVar(const Expr *Expression) {
if (const auto *Declaration = dyn_cast<DeclRefExpr>(Expression)) {
// It is a DeclRefExpr, so check if it's an ID-dependent variable.
const auto *CheckVariable = dyn_cast<VarDecl>(Declaration->getDecl());
auto FoundVariable = IdDepVarsMap.find(CheckVariable);
if (FoundVariable == IdDepVarsMap.end())
return nullptr;
return &(FoundVariable->second);
}
for (const auto *Child : Expression->children())
if (const auto *ChildExpression = dyn_cast<Expr>(Child))
if (IdDependencyRecord *Result = hasIdDepVar(ChildExpression))
return Result;
return nullptr;
}
IdDependentBackwardBranchCheck::IdDependencyRecord *
IdDependentBackwardBranchCheck::hasIdDepField(const Expr *Expression) {
if (const auto *MemberExpression = dyn_cast<MemberExpr>(Expression)) {
const auto *CheckField =
dyn_cast<FieldDecl>(MemberExpression->getMemberDecl());
auto FoundField = IdDepFieldsMap.find(CheckField);
if (FoundField == IdDepFieldsMap.end())
return nullptr;
return &(FoundField->second);
}
for (const auto *Child : Expression->children())
if (const auto *ChildExpression = dyn_cast<Expr>(Child))
if (IdDependencyRecord *Result = hasIdDepField(ChildExpression))
return Result;
return nullptr;
}
void IdDependentBackwardBranchCheck::saveIdDepVar(const Stmt *Statement,
const VarDecl *Variable) {
// Record that this variable is thread-dependent.
IdDepVarsMap[Variable] =
IdDependencyRecord(Variable, Variable->getBeginLoc(),
Twine("assignment of ID-dependent variable ") +
Variable->getNameAsString());
}
void IdDependentBackwardBranchCheck::saveIdDepField(const Stmt *Statement,
const FieldDecl *Field) {
// Record that this field is thread-dependent.
IdDepFieldsMap[Field] = IdDependencyRecord(
Field, Statement->getBeginLoc(),
Twine("assignment of ID-dependent field ") + Field->getNameAsString());
}
void IdDependentBackwardBranchCheck::saveIdDepVarFromReference(
const DeclRefExpr *RefExpr, const MemberExpr *MemExpr,
const VarDecl *PotentialVar) {
// If the variable is already in IdDepVarsMap, ignore it.
if (IdDepVarsMap.find(PotentialVar) != IdDepVarsMap.end())
return;
std::string Message;
llvm::raw_string_ostream StringStream(Message);
StringStream << "inferred assignment of ID-dependent value from "
"ID-dependent ";
if (RefExpr) {
const auto *RefVar = dyn_cast<VarDecl>(RefExpr->getDecl());
// If variable isn't ID-dependent, but RefVar is.
if (IdDepVarsMap.find(RefVar) != IdDepVarsMap.end())
StringStream << "variable " << RefVar->getNameAsString();
}
if (MemExpr) {
const auto *RefField = dyn_cast<FieldDecl>(MemExpr->getMemberDecl());
// If variable isn't ID-dependent, but RefField is.
if (IdDepFieldsMap.find(RefField) != IdDepFieldsMap.end())
StringStream << "member " << RefField->getNameAsString();
}
IdDepVarsMap[PotentialVar] =
IdDependencyRecord(PotentialVar, PotentialVar->getBeginLoc(), Message);
}
void IdDependentBackwardBranchCheck::saveIdDepFieldFromReference(
const DeclRefExpr *RefExpr, const MemberExpr *MemExpr,
const FieldDecl *PotentialField) {
// If the field is already in IdDepFieldsMap, ignore it.
if (IdDepFieldsMap.find(PotentialField) != IdDepFieldsMap.end())
return;
std::string Message;
llvm::raw_string_ostream StringStream(Message);
StringStream << "inferred assignment of ID-dependent member from "
"ID-dependent ";
if (RefExpr) {
const auto *RefVar = dyn_cast<VarDecl>(RefExpr->getDecl());
// If field isn't ID-dependent, but RefVar is.
if (IdDepVarsMap.find(RefVar) != IdDepVarsMap.end())
StringStream << "variable " << RefVar->getNameAsString();
}
if (MemExpr) {
const auto *RefField = dyn_cast<FieldDecl>(MemExpr->getMemberDecl());
if (IdDepFieldsMap.find(RefField) != IdDepFieldsMap.end())
StringStream << "member " << RefField->getNameAsString();
}
IdDepFieldsMap[PotentialField] = IdDependencyRecord(
PotentialField, PotentialField->getBeginLoc(), Message);
}
IdDependentBackwardBranchCheck::LoopType
IdDependentBackwardBranchCheck::getLoopType(const Stmt *Loop) {
switch (Loop->getStmtClass()) {
case Stmt::DoStmtClass:
return DoLoop;
case Stmt::WhileStmtClass:
return WhileLoop;
case Stmt::ForStmtClass:
return ForLoop;
default:
return UnknownLoop;
}
}
void IdDependentBackwardBranchCheck::check(
const MatchFinder::MatchResult &Result) {
// The first half of the callback only deals with identifying and storing
// ID-dependency information into the IdDepVars and IdDepFields maps.
const auto *Variable = Result.Nodes.getNodeAs<VarDecl>("tid_dep_var");
const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("tid_dep_field");
const auto *Statement = Result.Nodes.getNodeAs<Stmt>("straight_assignment");
const auto *RefExpr = Result.Nodes.getNodeAs<DeclRefExpr>("assign_ref_var");
const auto *MemExpr = Result.Nodes.getNodeAs<MemberExpr>("assign_ref_field");
const auto *PotentialVar = Result.Nodes.getNodeAs<VarDecl>("pot_tid_var");
const auto *PotentialField =
Result.Nodes.getNodeAs<FieldDecl>("pot_tid_field");
// Save variables and fields assigned directly through ID function calls.
if (Statement && (Variable || Field)) {
if (Variable)
saveIdDepVar(Statement, Variable);
else if (Field)
saveIdDepField(Statement, Field);
}
// Save variables assigned to values of Id-dependent variables and fields.
if ((RefExpr || MemExpr) && PotentialVar)
saveIdDepVarFromReference(RefExpr, MemExpr, PotentialVar);
// Save fields assigned to values of ID-dependent variables and fields.
if ((RefExpr || MemExpr) && PotentialField)
saveIdDepFieldFromReference(RefExpr, MemExpr, PotentialField);
// The second part of the callback deals with checking if a branch inside a
// loop is thread dependent.
const auto *CondExpr = Result.Nodes.getNodeAs<Expr>("cond_expr");
const auto *IDCall = Result.Nodes.getNodeAs<CallExpr>("id_call");
const auto *Loop = Result.Nodes.getNodeAs<Stmt>("backward_branch");
if (!Loop)
return;
LoopType Type = getLoopType(Loop);
if (CondExpr) {
if (IDCall) { // Conditional expression calls an ID function directly.
diag(CondExpr->getBeginLoc(),
"backward branch (%select{do|while|for}0 loop) is ID-dependent due "
"to ID function call and may cause performance degradation")
<< Type;
return;
}
// Conditional expression has DeclRefExpr(s), check ID-dependency.
IdDependencyRecord *IdDepVar = hasIdDepVar(CondExpr);
IdDependencyRecord *IdDepField = hasIdDepField(CondExpr);
if (IdDepVar) {
// Change one of these to a Note
diag(IdDepVar->Location, IdDepVar->Message, DiagnosticIDs::Note);
diag(CondExpr->getBeginLoc(),
"backward branch (%select{do|while|for}0 loop) is ID-dependent due "
"to variable reference to %1 and may cause performance degradation")
<< Type << IdDepVar->VariableDeclaration;
} else if (IdDepField) {
diag(IdDepField->Location, IdDepField->Message, DiagnosticIDs::Note);
diag(CondExpr->getBeginLoc(),
"backward branch (%select{do|while|for}0 loop) is ID-dependent due "
"to member reference to %1 and may cause performance degradation")
<< Type << IdDepField->FieldDeclaration;
}
}
}
} // namespace altera
} // namespace tidy
} // namespace clang
//===--- IdDependentBackwardBranchCheck.h - clang-tidy ----------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ALTERA_IDDEPENDENTBACKWARDBRANCHCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ALTERA_IDDEPENDENTBACKWARDBRANCHCHECK_H
#include "../ClangTidyCheck.h"
namespace clang {
namespace tidy {
namespace altera {
/// Finds ID-dependent variables and fields used within loops, and warns of
/// their usage. Using these variables in loops can lead to performance
/// degradation.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/altera-id-dependent-backward-branch.html
class IdDependentBackwardBranchCheck : public ClangTidyCheck {
private:
enum LoopType { UnknownLoop = -1, DoLoop = 0, WhileLoop = 1, ForLoop = 2 };
// Stores information necessary for printing out source of error.
struct IdDependencyRecord {
IdDependencyRecord(const VarDecl *Declaration, SourceLocation Location,
const llvm::Twine &Message)
: VariableDeclaration(Declaration), Location(Location),
Message(Message.str()) {}
IdDependencyRecord(const FieldDecl *Declaration, SourceLocation Location,
const llvm::Twine &Message)
: FieldDeclaration(Declaration), Location(Location),
Message(Message.str()) {}
IdDependencyRecord() = default;
const VarDecl *VariableDeclaration = nullptr;
const FieldDecl *FieldDeclaration = nullptr;
SourceLocation Location;
std::string Message;
};
// Stores the locations where ID-dependent variables are created.
std::map<const VarDecl *, IdDependencyRecord> IdDepVarsMap;
// Stores the locations where ID-dependent fields are created.
std::map<const FieldDecl *, IdDependencyRecord> IdDepFieldsMap;
/// Returns an IdDependencyRecord if the Expression contains an ID-dependent
/// variable, returns a nullptr otherwise.
IdDependencyRecord *hasIdDepVar(const Expr *Expression);
/// Returns an IdDependencyRecord if the Expression contains an ID-dependent
/// field, returns a nullptr otherwise.
IdDependencyRecord *hasIdDepField(const Expr *Expression);
/// Stores the location an ID-dependent variable is created from a call to
/// an ID function in IdDepVarsMap.
void saveIdDepVar(const Stmt *Statement, const VarDecl *Variable);
/// Stores the location an ID-dependent field is created from a call to an ID
/// function in IdDepFieldsMap.
void saveIdDepField(const Stmt *Statement, const FieldDecl *Field);
/// Stores the location an ID-dependent variable is created from a reference
/// to another ID-dependent variable or field in IdDepVarsMap.
void saveIdDepVarFromReference(const DeclRefExpr *RefExpr,
const MemberExpr *MemExpr,
const VarDecl *PotentialVar);
/// Stores the location an ID-dependent field is created from a reference to
/// another ID-dependent variable or field in IdDepFieldsMap.
void saveIdDepFieldFromReference(const DeclRefExpr *RefExpr,
const MemberExpr *MemExpr,
const FieldDecl *PotentialField);
/// Returns the loop type.
LoopType getLoopType(const Stmt *Loop);
public:
IdDependentBackwardBranchCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace altera
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ALTERA_IDDEPENDENTBACKWARDBRANCHCHECK_H
......@@ -58,9 +58,11 @@ void StructPackAlignCheck::check(const MatchFinder::MatchResult &Result) {
// For each StructField, record how big it is (in bits).
// Would be good to use a pair of <offset, size> to advise a better
// packing order.
QualType StructFieldTy = StructField->getType();
if (StructFieldTy->isIncompleteType())
return;
unsigned int StructFieldWidth =
(unsigned int)Result.Context
->getTypeInfo(StructField->getType().getTypePtr())
(unsigned int)Result.Context->getTypeInfo(StructFieldTy.getTypePtr())
.Width;
FieldSizes.emplace_back(StructFieldWidth, StructField->getFieldIndex());
// FIXME: Recommend a reorganization of the struct (sort by StructField
......
......@@ -21,6 +21,7 @@ namespace bugprone {
static internal::Matcher<Stmt>
loopEndingStmt(internal::Matcher<Stmt> Internal) {
// FIXME: Cover noreturn ObjC methods (and blocks?).
return stmt(anyOf(
mapAnyOf(breakStmt, returnStmt, gotoStmt, cxxThrowExpr).with(Internal),
callExpr(Internal, callee(functionDecl(isNoReturn())))));
......@@ -43,9 +44,8 @@ static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var,
}
/// Return whether `Cond` is a variable that is possibly changed in `LoopStmt`.
static bool isVarThatIsPossiblyChanged(const FunctionDecl *Func,
const Stmt *LoopStmt, const Stmt *Cond,
ASTContext *Context) {
static bool isVarThatIsPossiblyChanged(const Decl *Func, const Stmt *LoopStmt,
const Stmt *Cond, ASTContext *Context) {
if (const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
if (!Var->isLocalVarDeclOrParm())
......@@ -61,7 +61,8 @@ static bool isVarThatIsPossiblyChanged(const FunctionDecl *Func,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
} else if (isa<MemberExpr>(Cond) || isa<CallExpr>(Cond)) {
} else if (isa<MemberExpr, CallExpr,
ObjCIvarRefExpr, ObjCPropertyRefExpr, ObjCMessageExpr>(Cond)) {
// FIXME: Handle MemberExpr.
return true;
}
......@@ -70,9 +71,8 @@ static bool isVarThatIsPossiblyChanged(const FunctionDecl *Func,
}
/// Return whether at least one variable of `Cond` changed in `LoopStmt`.
static bool isAtLeastOneCondVarChanged(const FunctionDecl *Func,
const Stmt *LoopStmt, const Stmt *Cond,
ASTContext *Context) {
static bool isAtLeastOneCondVarChanged(const Decl *Func, const Stmt *LoopStmt,
const Stmt *Cond, ASTContext *Context) {
if (isVarThatIsPossiblyChanged(Func, LoopStmt, Cond, Context))
return true;
......@@ -118,9 +118,9 @@ static bool isKnownFalse(const Expr &Cond, const ASTContext &Ctx) {
void InfiniteLoopCheck::registerMatchers(MatchFinder *Finder) {
const auto LoopCondition = allOf(
hasCondition(
expr(forFunction(functionDecl().bind("func"))).bind("condition")),
expr(forCallable(decl().bind("func"))).bind("condition")),
unless(hasBody(hasDescendant(
loopEndingStmt(forFunction(equalsBoundNode("func")))))));
loopEndingStmt(forCallable(equalsBoundNode("func")))))));
Finder->addMatcher(mapAnyOf(whileStmt, doStmt, forStmt)
.with(LoopCondition)
......@@ -131,7 +131,7 @@ void InfiniteLoopCheck::registerMatchers(MatchFinder *Finder) {
void InfiniteLoopCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Cond = Result.Nodes.getNodeAs<Expr>("condition");
const auto *LoopStmt = Result.Nodes.getNodeAs<Stmt>("loop-stmt");
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
const auto *Func = Result.Nodes.getNodeAs<Decl>("func");
if (isKnownFalse(*Cond, *Result.Context))
return;
......
......@@ -90,11 +90,8 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
const auto IntegerCallExpr = ignoringParenImpCasts(
callExpr(anyOf(hasType(isInteger()), hasType(enumType())),
unless(isInTemplateInstantiation())));
const auto SizeOfExpr = expr(anyOf(
sizeOfExpr(
has(hasUnqualifiedDesugaredType(type().bind("sizeof-arg-type")))),
sizeOfExpr(has(expr(hasType(
hasUnqualifiedDesugaredType(type().bind("sizeof-arg-type"))))))));
const auto SizeOfExpr = sizeOfExpr(hasArgumentOfType(
hasUnqualifiedDesugaredType(type().bind("sizeof-arg-type"))));
const auto SizeOfZero =
sizeOfExpr(has(ignoringParenImpCasts(integerLiteral(equals(0)))));
......@@ -184,9 +181,8 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
binaryOperator(matchers::isRelationalOperator(),
hasOperands(ignoringParenImpCasts(SizeOfExpr),
ignoringParenImpCasts(anyOf(
integerLiteral(equals(0)),
integerLiteral(isBiggerThan(0x80000))))))
ignoringParenImpCasts(integerLiteral(anyOf(
equals(0), isBiggerThan(0x80000))))))
.bind("sizeof-compare-constant"),
this);
}
......@@ -207,18 +203,15 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
const auto ElemType =
arrayType(hasElementType(recordType().bind("elem-type")));
const auto ElemPtrType = pointerType(pointee(type().bind("elem-ptr-type")));
const auto NumType = hasCanonicalType(
type(anyOf(ElemType, ElemPtrType, type())).bind("num-type"));
const auto DenomType = hasCanonicalType(type().bind("denom-type"));
Finder->addMatcher(
binaryOperator(hasOperatorName("/"),
hasLHS(expr(ignoringParenImpCasts(
anyOf(sizeOfExpr(has(NumType)),
sizeOfExpr(has(expr(hasType(NumType)))))))),
hasRHS(expr(ignoringParenImpCasts(
anyOf(sizeOfExpr(has(DenomType)),
sizeOfExpr(has(expr(hasType(DenomType)))))))))
binaryOperator(
hasOperatorName("/"),
hasLHS(ignoringParenImpCasts(sizeOfExpr(hasArgumentOfType(
hasCanonicalType(type(anyOf(ElemType, ElemPtrType, type()))
.bind("num-type")))))),
hasRHS(ignoringParenImpCasts(sizeOfExpr(
hasArgumentOfType(hasCanonicalType(type().bind("denom-type")))))))
.bind("sizeof-divide-expr"),
this);
......
......@@ -32,7 +32,7 @@ void SuspiciousMemsetUsageCheck::registerMatchers(MatchFinder *Finder) {
// Look for memset(x, '0', z). Probably memset(x, 0, z) was intended.
Finder->addMatcher(
callExpr(
callee(MemsetDecl),
callee(MemsetDecl), argumentCountIs(3),
hasArgument(1, characterLiteral(equals(static_cast<unsigned>('0')))