Skip to content

Commit

Permalink
Merged main:4564553b8d8a into amd-gfx:ca4735522f1c
Browse files Browse the repository at this point in the history
Local branch amd-gfx ca47355 Merged main:75eca67c1c4b into amd-gfx:57dffbe52491
Remote branch main 4564553 [WebAssembly] Support COMDAT sections in assembly syntax
  • Loading branch information
Sw authored and Sw committed Dec 10, 2020
2 parents ca47355 + 4564553 commit 47ff52e
Show file tree
Hide file tree
Showing 36 changed files with 705 additions and 218 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ namespace tidy {
namespace performance {
namespace {

using namespace ::clang::ast_matchers;
using llvm::StringRef;
using utils::decl_ref_expr::isOnlyUsedAsConst;

static constexpr StringRef ObjectArgId = "objectArg";
static constexpr StringRef InitFunctionCallId = "initFunctionCall";
static constexpr StringRef OldVarDeclId = "oldVarDecl";

void recordFixes(const VarDecl &Var, ASTContext &Context,
DiagnosticBuilder &Diagnostic) {
Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
Expand All @@ -29,10 +37,88 @@ void recordFixes(const VarDecl &Var, ASTContext &Context,
}
}

} // namespace
AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) {
// Match method call expressions where the `this` argument is only used as
// const, this will be checked in `check()` part. This returned const
// reference is highly likely to outlive the local const reference of the
// variable being declared. The assumption is that the const reference being
// returned either points to a global static variable or to a member of the
// called object.
return cxxMemberCallExpr(
callee(cxxMethodDecl(returns(matchers::isReferenceToConst()))),
on(declRefExpr(to(varDecl().bind(ObjectArgId)))));
}

using namespace ::clang::ast_matchers;
using utils::decl_ref_expr::isOnlyUsedAsConst;
AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {
// Only allow initialization of a const reference from a free function if it
// has no arguments. Otherwise it could return an alias to one of its
// arguments and the arguments need to be checked for const use as well.
return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst()))),
argumentCountIs(0), unless(callee(cxxMethodDecl())))
.bind(InitFunctionCallId);
}

AST_MATCHER_FUNCTION(StatementMatcher, isInitializedFromReferenceToConst) {
auto OldVarDeclRef =
declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId)));
return declStmt(has(varDecl(hasInitializer(
anyOf(isConstRefReturningFunctionCall(), isConstRefReturningMethodCall(),
ignoringImpCasts(OldVarDeclRef),
ignoringImpCasts(unaryOperator(
hasOperatorName("&"), hasUnaryOperand(OldVarDeclRef))))))));
}

// This checks that the variable itself is only used as const, and also makes
// sure that it does not reference another variable that could be modified in
// the BlockStmt. It does this by checking the following:
// 1. If the variable is neither a reference nor a pointer then the
// isOnlyUsedAsConst() check is sufficient.
// 2. If the (reference or pointer) variable is not initialized in a DeclStmt in
// the BlockStmt. In this case its pointee is likely not modified (unless it
// is passed as an alias into the method as well).
// 3. If the reference is initialized from a reference to const. This is
// the same set of criteria we apply when identifying the unnecessary copied
// variable in this check to begin with. In this case we check whether the
// object arg or variable that is referenced is immutable as well.
static bool isInitializingVariableImmutable(const VarDecl &InitializingVar,
const Stmt &BlockStmt,
ASTContext &Context) {
if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
return false;

QualType T = InitializingVar.getType();
// The variable is a value type and we know it is only used as const. Safe
// to reference it and avoid the copy.
if (!isa<ReferenceType, PointerType>(T))
return true;

auto Matches =
match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar))))
.bind("declStmt")),
BlockStmt, Context);
// The reference or pointer is not initialized in the BlockStmt. We assume
// its pointee is not modified then.
if (Matches.empty())
return true;

const auto *Initialization = selectFirst<DeclStmt>("declStmt", Matches);
Matches =
match(isInitializedFromReferenceToConst(), *Initialization, Context);
// The reference is initialized from a free function without arguments
// returning a const reference. This is a global immutable object.
if (selectFirst<CallExpr>(InitFunctionCallId, Matches) != nullptr)
return true;
// Check that the object argument is immutable as well.
if (const auto *OrigVar = selectFirst<VarDecl>(ObjectArgId, Matches))
return isInitializingVariableImmutable(*OrigVar, BlockStmt, Context);
// Check that the old variable we reference is immutable as well.
if (const auto *OrigVar = selectFirst<VarDecl>(OldVarDeclId, Matches))
return isInitializingVariableImmutable(*OrigVar, BlockStmt, Context);

return false;
}

} // namespace

UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
StringRef Name, ClangTidyContext *Context)
Expand All @@ -41,22 +127,6 @@ UnnecessaryCopyInitialization::UnnecessaryCopyInitialization(
utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}

void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
auto ConstReference = referenceType(pointee(qualType(isConstQualified())));

// Match method call expressions where the `this` argument is only used as
// const, this will be checked in `check()` part. This returned const
// reference is highly likely to outlive the local const reference of the
// variable being declared. The assumption is that the const reference being
// returned either points to a global static variable or to a member of the
// called object.
auto ConstRefReturningMethodCall =
cxxMemberCallExpr(callee(cxxMethodDecl(returns(ConstReference))),
on(declRefExpr(to(varDecl().bind("objectArg")))));
auto ConstRefReturningFunctionCall =
callExpr(callee(functionDecl(returns(ConstReference))),
unless(callee(cxxMethodDecl())))
.bind("initFunctionCall");

auto localVarCopiedFrom = [this](const internal::Matcher<Expr> &CopyCtorArg) {
return compoundStmt(
forEachDescendant(
Expand All @@ -83,24 +153,22 @@ void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
.bind("blockStmt");
};

Finder->addMatcher(localVarCopiedFrom(anyOf(ConstRefReturningFunctionCall,
ConstRefReturningMethodCall)),
Finder->addMatcher(localVarCopiedFrom(anyOf(isConstRefReturningFunctionCall(),
isConstRefReturningMethodCall())),
this);

Finder->addMatcher(localVarCopiedFrom(declRefExpr(
to(varDecl(hasLocalStorage()).bind("oldVarDecl")))),
to(varDecl(hasLocalStorage()).bind(OldVarDeclId)))),
this);
}

void UnnecessaryCopyInitialization::check(
const MatchFinder::MatchResult &Result) {
const auto *NewVar = Result.Nodes.getNodeAs<VarDecl>("newVarDecl");
const auto *OldVar = Result.Nodes.getNodeAs<VarDecl>("oldVarDecl");
const auto *ObjectArg = Result.Nodes.getNodeAs<VarDecl>("objectArg");
const auto *OldVar = Result.Nodes.getNodeAs<VarDecl>(OldVarDeclId);
const auto *ObjectArg = Result.Nodes.getNodeAs<VarDecl>(ObjectArgId);
const auto *BlockStmt = Result.Nodes.getNodeAs<Stmt>("blockStmt");
const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>("ctorCall");
const auto *InitFunctionCall =
Result.Nodes.getNodeAs<CallExpr>("initFunctionCall");

TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs);

Expand All @@ -118,11 +186,6 @@ void UnnecessaryCopyInitialization::check(
return;

if (OldVar == nullptr) {
// Only allow initialization of a const reference from a free function if it
// has no arguments. Otherwise it could return an alias to one of its
// arguments and the arguments need to be checked for const use as well.
if (InitFunctionCall != nullptr && InitFunctionCall->getNumArgs() > 0)
return;
handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg,
*Result.Context);
} else {
Expand All @@ -138,7 +201,7 @@ void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
return;
if (ObjectArg != nullptr &&
!isOnlyUsedAsConst(*ObjectArg, BlockStmt, Context))
!isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context))
return;

auto Diagnostic =
Expand All @@ -158,7 +221,7 @@ void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
bool IssueFix, ASTContext &Context) {
if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
!isOnlyUsedAsConst(OldVar, BlockStmt, Context))
!isInitializingVariableImmutable(OldVar, BlockStmt, Context))
return;

auto Diagnostic = diag(NewVar.getLocation(),
Expand Down
16 changes: 15 additions & 1 deletion clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt,
SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
extractNodesByIdTo(Matches, "declRef", DeclRefs);
auto ConstReferenceOrValue =
qualType(anyOf(referenceType(pointee(qualType(isConstQualified()))),
qualType(anyOf(matchers::isReferenceToConst(),
unless(anyOf(referenceType(), pointerType(),
substTemplateTypeParmType()))));
auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
Expand All @@ -71,6 +71,20 @@ constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt,
Matches =
match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
extractNodesByIdTo(Matches, "declRef", DeclRefs);
// References and pointers to const assignments.
Matches =
match(findAll(declStmt(
has(varDecl(hasType(qualType(matchers::isReferenceToConst())),
hasInitializer(ignoringImpCasts(DeclRefToVar)))))),
Stmt, Context);
extractNodesByIdTo(Matches, "declRef", DeclRefs);
Matches =
match(findAll(declStmt(has(varDecl(
hasType(qualType(matchers::isPointerToConst())),
hasInitializer(ignoringImpCasts(unaryOperator(
hasOperatorName("&"), hasUnaryOperand(DeclRefToVar)))))))),
Stmt, Context);
extractNodesByIdTo(Matches, "declRef", DeclRefs);
return DeclRefs;
}

Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/clang-tidy/utils/Matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isReferenceToConst) {
return referenceType(pointee(qualType(isConstQualified())));
}

// Returns QualType matcher for pointers to const.
AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
using namespace ast_matchers;
return pointerType(pointee(qualType(isConstQualified())));
}

AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector<std::string>,
NameList) {
return llvm::any_of(NameList, [&Node](const std::string &Name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,35 @@ void negativeInvokedOnStdFunction(
auto Copy = Orig.reference();
Update(Copy);
}

void negativeCopiedFromReferenceToModifiedVar() {
ExpensiveToCopyType Orig;
const auto &Ref = Orig;
const auto NecessaryCopy = Ref;
Orig.nonConstMethod();
}

void positiveCopiedFromReferenceToConstVar() {
ExpensiveToCopyType Orig;
const auto &Ref = Orig;
const auto UnnecessaryCopy = Ref;
// CHECK-MESSAGES: [[@LINE-1]]:14: warning: local copy 'UnnecessaryCopy' of
// CHECK-FIXES: const auto& UnnecessaryCopy = Ref;
Orig.constMethod();
}

void negativeCopiedFromGetterOfReferenceToModifiedVar() {
ExpensiveToCopyType Orig;
const auto &Ref = Orig.reference();
const auto NecessaryCopy = Ref.reference();
Orig.nonConstMethod();
}

void positiveCopiedFromGetterOfReferenceToConstVar() {
ExpensiveToCopyType Orig;
const auto &Ref = Orig.reference();
auto UnnecessaryCopy = Ref.reference();
// CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'UnnecessaryCopy' is
// CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference();
Orig.constMethod();
}
12 changes: 6 additions & 6 deletions clang/include/clang/Basic/FileEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,13 +328,13 @@ class FileEntry {
friend class FileManager;

std::string RealPathName; // Real path to the file; could be empty.
off_t Size; // File size in bytes.
time_t ModTime; // Modification time of file.
const DirectoryEntry *Dir; // Directory file lives in.
off_t Size = 0; // File size in bytes.
time_t ModTime = 0; // Modification time of file.
const DirectoryEntry *Dir = nullptr; // Directory file lives in.
llvm::sys::fs::UniqueID UniqueID;
unsigned UID; // A unique (small) ID for the file.
bool IsNamedPipe;
bool IsValid; // Is this \c FileEntry initialized and valid?
unsigned UID = 0; // A unique (small) ID for the file.
bool IsNamedPipe = false;
bool IsValid = false; // Is this \c FileEntry initialized and valid?

/// The open file, if it is owned by the \p FileEntry.
mutable std::unique_ptr<llvm::vfs::File> File;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/FileEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

using namespace clang;

FileEntry::FileEntry() : UniqueID(0, 0), IsNamedPipe(false), IsValid(false) {}
FileEntry::FileEntry() : UniqueID(0, 0) {}

FileEntry::~FileEntry() = default;

Expand Down
11 changes: 11 additions & 0 deletions clang/unittests/Basic/FileEntryTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ struct RefMaps {
}
};

TEST(FileEntryTest, Constructor) {
FileEntry FE;
EXPECT_EQ(0U, FE.getSize());
EXPECT_EQ(0, FE.getModificationTime());
EXPECT_EQ(nullptr, FE.getDir());
EXPECT_EQ(0U, FE.getUniqueID().getDevice());
EXPECT_EQ(0U, FE.getUniqueID().getFile());
EXPECT_EQ(false, FE.isNamedPipe());
EXPECT_EQ(false, FE.isValid());
}

TEST(FileEntryTest, FileEntryRef) {
RefMaps Refs;
FileEntryRef R1 = Refs.addFile("1");
Expand Down
12 changes: 12 additions & 0 deletions compiler-rt/lib/dfsan/dfsan_custom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,18 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
return rv;
}

SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread,
void **retval,
dfsan_label thread_label,
dfsan_label retval_label,
dfsan_label *ret_label) {
int ret = pthread_join(thread, retval);
if (ret == 0 && retval)
dfsan_set_label(0, retval, sizeof(*retval));
*ret_label = 0;
return ret;
}

struct dl_iterate_phdr_info {
int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
size_t size, void *data, dfsan_label info_label,
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/dfsan/done_abilist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ fun:pthread_setspecific=discard
# Functions that take a callback (wrap the callback manually).
fun:pthread_create=custom

# Functions that produce output does not depend on the input (need to zero the
# shadow manually).
fun:pthread_join=custom

###############################################################################
# libffi/libgo
###############################################################################
Expand Down
1 change: 0 additions & 1 deletion compiler-rt/lib/msan/msan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ static void InitializeFlags() {
// FIXME: test and enable.
cf.check_printf = false;
cf.intercept_tls_get_addr = true;
cf.exitcode = 77;
OverrideCommonFlags(cf);
}

Expand Down
11 changes: 10 additions & 1 deletion compiler-rt/test/dfsan/custom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,10 +792,18 @@ void test_pthread_create() {
pthread_t pt;
pthread_create(&pt, 0, pthread_create_test_cb, (void *)1);
void *cbrv;
pthread_join(pt, &cbrv);
dfsan_set_label(i_label, &cbrv, sizeof(cbrv));
int ret = pthread_join(pt, &cbrv);
assert(ret == 0);
assert(cbrv == (void *)2);
ASSERT_ZERO_LABEL(ret);
ASSERT_ZERO_LABEL(cbrv);
}

// Tested by test_pthread_create(). This empty function is here to appease the
// check-wrappers script.
void test_pthread_join() {}

int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
void *data) {
assert(data == (void *)3);
Expand Down Expand Up @@ -1216,6 +1224,7 @@ int main(void) {
test_poll();
test_pread();
test_pthread_create();
test_pthread_join();
test_read();
test_recvmsg();
test_sched_getaffinity();
Expand Down
Loading

0 comments on commit 47ff52e

Please sign in to comment.