143 changes: 79 additions & 64 deletions bolt/lib/Profile/BoltAddressTranslation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

#include "bolt/Profile/BoltAddressTranslation.h"
#include "bolt/Core/BinaryFunction.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/LEB128.h"

#define DEBUG_TYPE "bolt-bat"

Expand Down Expand Up @@ -44,7 +45,7 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,
// and this deleted block will both share the same output address (the same
// key), and we need to map back. We choose here to privilege the successor by
// allowing it to overwrite the previously inserted key in the map.
Map[BBOutputOffset] = BBInputOffset;
Map[BBOutputOffset] = BBInputOffset << 1;

const auto &IOAddressMap =
BB.getFunction()->getBinaryContext().getIOAddressMap();
Expand All @@ -61,8 +62,8 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,

LLVM_DEBUG(dbgs() << " Key: " << Twine::utohexstr(OutputOffset) << " Val: "
<< Twine::utohexstr(InputOffset) << " (branch)\n");
Map.insert(
std::pair<uint32_t, uint32_t>(OutputOffset, InputOffset | BRANCHENTRY));
Map.insert(std::pair<uint32_t, uint32_t>(OutputOffset,
(InputOffset << 1) | BRANCHENTRY));
}
}

Expand Down Expand Up @@ -101,36 +102,51 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
}
}

const uint32_t NumFuncs = Maps.size();
OS.write(reinterpret_cast<const char *>(&NumFuncs), 4);
LLVM_DEBUG(dbgs() << "Writing " << NumFuncs << " functions for BAT.\n");
writeMaps</*Cold=*/false>(Maps, OS);
writeMaps</*Cold=*/true>(Maps, OS);

outs() << "BOLT-INFO: Wrote " << Maps.size() << " BAT maps\n";
}

template <bool Cold>
void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
raw_ostream &OS) {
const uint32_t NumFuncs =
llvm::count_if(llvm::make_first_range(Maps), [&](const uint64_t Address) {
return Cold == ColdPartSource.count(Address);
});
encodeULEB128(NumFuncs, OS);
LLVM_DEBUG(dbgs() << "Writing " << NumFuncs << (Cold ? " cold" : "")
<< " functions for BAT.\n");
size_t PrevIndex = 0;
// Output addresses are delta-encoded
uint64_t PrevAddress = 0;
for (auto &MapEntry : Maps) {
const uint64_t Address = MapEntry.first;
// Only process cold fragments in cold mode, and vice versa.
if (Cold != ColdPartSource.count(Address))
continue;
MapTy &Map = MapEntry.second;
const uint32_t NumEntries = Map.size();
LLVM_DEBUG(dbgs() << "Writing " << NumEntries << " entries for 0x"
<< Twine::utohexstr(Address) << ".\n");
OS.write(reinterpret_cast<const char *>(&Address), 8);
OS.write(reinterpret_cast<const char *>(&NumEntries), 4);
encodeULEB128(Address - PrevAddress, OS);
PrevAddress = Address;
if (Cold) {
size_t HotIndex =
std::distance(ColdPartSource.begin(), ColdPartSource.find(Address));
encodeULEB128(HotIndex - PrevIndex, OS);
PrevIndex = HotIndex;
}
encodeULEB128(NumEntries, OS);
uint64_t InOffset = 0, OutOffset = 0;
// Output and Input addresses and delta-encoded
for (std::pair<const uint32_t, uint32_t> &KeyVal : Map) {
OS.write(reinterpret_cast<const char *>(&KeyVal.first), 4);
OS.write(reinterpret_cast<const char *>(&KeyVal.second), 4);
encodeULEB128(KeyVal.first - OutOffset, OS);
encodeSLEB128(KeyVal.second - InOffset, OS);
std::tie(OutOffset, InOffset) = KeyVal;
}
}
const uint32_t NumColdEntries = ColdPartSource.size();
LLVM_DEBUG(dbgs() << "Writing " << NumColdEntries
<< " cold part mappings.\n");
OS.write(reinterpret_cast<const char *>(&NumColdEntries), 4);
for (std::pair<const uint64_t, uint64_t> &ColdEntry : ColdPartSource) {
OS.write(reinterpret_cast<const char *>(&ColdEntry.first), 8);
OS.write(reinterpret_cast<const char *>(&ColdEntry.second), 8);
LLVM_DEBUG(dbgs() << " " << Twine::utohexstr(ColdEntry.first) << " -> "
<< Twine::utohexstr(ColdEntry.second) << "\n");
}

outs() << "BOLT-INFO: Wrote " << Maps.size() << " BAT maps\n";
outs() << "BOLT-INFO: Wrote " << NumColdEntries
<< " BAT cold-to-hot entries\n";
}

std::error_code BoltAddressTranslation::parse(StringRef Buf) {
Expand All @@ -152,53 +168,52 @@ std::error_code BoltAddressTranslation::parse(StringRef Buf) {
if (Name.substr(0, 4) != "BOLT")
return make_error_code(llvm::errc::io_error);

if (Buf.size() - Offset < 4)
return make_error_code(llvm::errc::io_error);
Error Err(Error::success());
std::vector<uint64_t> HotFuncs;
parseMaps</*Cold=*/false>(HotFuncs, DE, Offset, Err);
parseMaps</*Cold=*/true>(HotFuncs, DE, Offset, Err);
outs() << "BOLT-INFO: Parsed " << Maps.size() << " BAT entries\n";
return errorToErrorCode(std::move(Err));
}

const uint32_t NumFunctions = DE.getU32(&Offset);
LLVM_DEBUG(dbgs() << "Parsing " << NumFunctions << " functions\n");
template <bool Cold>
void BoltAddressTranslation::parseMaps(std::vector<uint64_t> &HotFuncs,
DataExtractor &DE, uint64_t &Offset,
Error &Err) {
const uint32_t NumFunctions = DE.getULEB128(&Offset, &Err);
LLVM_DEBUG(dbgs() << "Parsing " << NumFunctions << (Cold ? " cold" : "")
<< " functions\n");
size_t HotIndex = 0;
uint64_t PrevAddress = 0;
for (uint32_t I = 0; I < NumFunctions; ++I) {
if (Buf.size() - Offset < 12)
return make_error_code(llvm::errc::io_error);

const uint64_t Address = DE.getU64(&Offset);
const uint32_t NumEntries = DE.getU32(&Offset);
const uint64_t Address = PrevAddress + DE.getULEB128(&Offset, &Err);
PrevAddress = Address;
if (Cold) {
HotIndex += DE.getULEB128(&Offset, &Err);
ColdPartSource.emplace(Address, HotFuncs[HotIndex]);
} else {
HotFuncs.push_back(Address);
}
const uint32_t NumEntries = DE.getULEB128(&Offset, &Err);
MapTy Map;

LLVM_DEBUG(dbgs() << "Parsing " << NumEntries << " entries for 0x"
<< Twine::utohexstr(Address) << "\n");
if (Buf.size() - Offset < 8 * NumEntries)
return make_error_code(llvm::errc::io_error);
uint64_t InputOffset = 0, OutputOffset = 0;
for (uint32_t J = 0; J < NumEntries; ++J) {
const uint32_t OutputAddr = DE.getU32(&Offset);
const uint32_t InputAddr = DE.getU32(&Offset);
Map.insert(std::pair<uint32_t, uint32_t>(OutputAddr, InputAddr));
LLVM_DEBUG(dbgs() << Twine::utohexstr(OutputAddr) << " -> "
<< Twine::utohexstr(InputAddr) << "\n");
const uint64_t OutputDelta = DE.getULEB128(&Offset, &Err);
const int64_t InputDelta = DE.getSLEB128(&Offset, &Err);
OutputOffset += OutputDelta;
InputOffset += InputDelta;
Map.insert(std::pair<uint32_t, uint32_t>(OutputOffset, InputOffset));
LLVM_DEBUG(dbgs() << formatv("{0:x} -> {1:x} ({2}/{3}b -> {4}/{5}b)\n",
OutputOffset, InputOffset, OutputDelta,
encodeULEB128(OutputDelta, nulls()),
InputDelta,
encodeSLEB128(InputDelta, nulls())));
}
Maps.insert(std::pair<uint64_t, MapTy>(Address, Map));
}

if (Buf.size() - Offset < 4)
return make_error_code(llvm::errc::io_error);

const uint32_t NumColdEntries = DE.getU32(&Offset);
LLVM_DEBUG(dbgs() << "Parsing " << NumColdEntries << " cold part mappings\n");
for (uint32_t I = 0; I < NumColdEntries; ++I) {
if (Buf.size() - Offset < 16)
return make_error_code(llvm::errc::io_error);
const uint32_t ColdAddress = DE.getU64(&Offset);
const uint32_t HotAddress = DE.getU64(&Offset);
ColdPartSource.insert(
std::pair<uint64_t, uint64_t>(ColdAddress, HotAddress));
LLVM_DEBUG(dbgs() << Twine::utohexstr(ColdAddress) << " -> "
<< Twine::utohexstr(HotAddress) << "\n");
}
outs() << "BOLT-INFO: Parsed " << Maps.size() << " BAT entries\n";
outs() << "BOLT-INFO: Parsed " << NumColdEntries
<< " BAT cold-to-hot entries\n";

return std::error_code();
}

void BoltAddressTranslation::dump(raw_ostream &OS) {
Expand All @@ -209,7 +224,7 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
OS << "BB mappings:\n";
for (const auto &Entry : MapEntry.second) {
const bool IsBranch = Entry.second & BRANCHENTRY;
const uint32_t Val = Entry.second & ~BRANCHENTRY;
const uint32_t Val = Entry.second >> 1; // dropping BRANCHENTRY bit
OS << "0x" << Twine::utohexstr(Entry.first) << " -> "
<< "0x" << Twine::utohexstr(Val);
if (IsBranch)
Expand Down Expand Up @@ -244,7 +259,7 @@ uint64_t BoltAddressTranslation::translate(uint64_t FuncAddress,

--KeyVal;

const uint32_t Val = KeyVal->second & ~BRANCHENTRY;
const uint32_t Val = KeyVal->second >> 1; // dropping BRANCHENTRY bit
// Branch source addresses are translated to the first instruction of the
// source BB to avoid accounting for modifications BOLT may have made in the
// BB regarding deletion/addition of instructions.
Expand Down
2 changes: 1 addition & 1 deletion bolt/lib/Rewrite/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ set(LLVM_LINK_COMPONENTS
MC
Object
Support
DWARFLinkerBase
DWARFLinker
DWARFLinkerClassic
AsmPrinter
TargetParser
)
Expand Down
1 change: 1 addition & 0 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4112,6 +4112,7 @@ void RewriteInstance::encodeBATSection() {
copyByteArray(BoltInfo), BoltInfo.size(),
/*Alignment=*/1,
/*IsReadOnly=*/true, ELF::SHT_NOTE);
outs() << "BOLT-INFO: BAT section size (bytes): " << BoltInfo.size() << '\n';
}

template <typename ELFShdrTy>
Expand Down
2 changes: 1 addition & 1 deletion bolt/test/X86/bolt-address-translation.test
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#
# CHECK: BOLT: 3 out of 7 functions were overwritten.
# CHECK: BOLT-INFO: Wrote 6 BAT maps
# CHECK: BOLT-INFO: Wrote 3 BAT cold-to-hot entries
# CHECK: BOLT-INFO: BAT section size (bytes): 404
#
# usqrt mappings (hot part). We match against any key (left side containing
# the bolted binary offsets) because BOLT may change where it puts instructions
Expand Down
10 changes: 9 additions & 1 deletion clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "StaticAssertCheck.h"
#include "../utils/Matchers.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
Expand Down Expand Up @@ -45,13 +46,20 @@ void StaticAssertCheck::registerMatchers(MatchFinder *Finder) {
IsAlwaysFalse);
auto NonConstexprFunctionCall =
callExpr(hasDeclaration(functionDecl(unless(isConstexpr()))));
auto NonConstexprVariableReference =
declRefExpr(to(varDecl(unless(isConstexpr()))),
unless(hasAncestor(expr(matchers::hasUnevaluatedContext()))),
unless(hasAncestor(typeLoc())));

auto NonConstexprCode =
expr(anyOf(NonConstexprFunctionCall, NonConstexprVariableReference));
auto AssertCondition =
expr(
anyOf(expr(ignoringParenCasts(anyOf(
AssertExprRoot, unaryOperator(hasUnaryOperand(
ignoringParenCasts(AssertExprRoot)))))),
anything()),
unless(findAll(NonConstexprFunctionCall)))
unless(NonConstexprCode), unless(hasDescendant(NonConstexprCode)))
.bind("condition");
auto Condition =
anyOf(ignoringParenImpCasts(callExpr(
Expand Down
23 changes: 13 additions & 10 deletions clang-tools-extra/clangd/CompileCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,26 +313,29 @@ void CommandMangler::operator()(tooling::CompileCommand &Command,

tooling::addTargetAndModeForProgramName(Cmd, Cmd.front());

// Check whether the flag exists, either as -flag or -flag=*
auto Has = [&](llvm::StringRef Flag) {
for (llvm::StringRef Arg : Cmd) {
if (Arg.consume_front(Flag) && (Arg.empty() || Arg[0] == '='))
return true;
}
return false;
// Check whether the flag exists in the command.
auto HasExact = [&](llvm::StringRef Flag) {
return llvm::any_of(Cmd, [&](llvm::StringRef Arg) { return Arg == Flag; });
};

// Check whether the flag appears in the command as a prefix.
auto HasPrefix = [&](llvm::StringRef Flag) {
return llvm::any_of(
Cmd, [&](llvm::StringRef Arg) { return Arg.starts_with(Flag); });
};

llvm::erase_if(Cmd, [](llvm::StringRef Elem) {
return Elem.starts_with("--save-temps") || Elem.starts_with("-save-temps");
});

std::vector<std::string> ToAppend;
if (ResourceDir && !Has("-resource-dir"))
if (ResourceDir && !HasExact("-resource-dir") && !HasPrefix("-resource-dir="))
ToAppend.push_back(("-resource-dir=" + *ResourceDir));

// Don't set `-isysroot` if it is already set or if `--sysroot` is set.
// `--sysroot` is a superset of the `-isysroot` argument.
if (Sysroot && !Has("-isysroot") && !Has("--sysroot")) {
if (Sysroot && !HasPrefix("-isysroot") && !HasExact("--sysroot") &&
!HasPrefix("--sysroot=")) {
ToAppend.push_back("-isysroot");
ToAppend.push_back(*Sysroot);
}
Expand All @@ -343,7 +346,7 @@ void CommandMangler::operator()(tooling::CompileCommand &Command,
}

if (!Cmd.empty()) {
bool FollowSymlink = !Has("-no-canonical-prefixes");
bool FollowSymlink = !HasExact("-no-canonical-prefixes");
Cmd.front() =
(FollowSymlink ? ResolvedDrivers : ResolvedDriversNoFollow)
.get(Cmd.front(), [&, this] {
Expand Down
81 changes: 78 additions & 3 deletions clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,8 @@ TEST(ArgStripperTest, OrderDependent) {
}

TEST(PrintArgvTest, All) {
std::vector<llvm::StringRef> Args = {
"one", "two", "thr ee", "f\"o\"ur", "fi\\ve", "$"
};
std::vector<llvm::StringRef> Args = {"one", "two", "thr ee",
"f\"o\"ur", "fi\\ve", "$"};
const char *Expected = R"(one two "thr ee" "f\"o\"ur" "fi\\ve" $)";
EXPECT_EQ(Expected, printArgv(Args));
}
Expand Down Expand Up @@ -450,6 +449,82 @@ TEST(CommandMangler, PathsAsPositional) {
Mangler(Cmd, "a.cc");
EXPECT_THAT(Cmd.CommandLine, Contains("foo"));
}

TEST(CommandMangler, RespectsOriginalResourceDir) {
auto Mangler = CommandMangler::forTests();
Mangler.ResourceDir = testPath("fake/resources");

{
tooling::CompileCommand Cmd;
Cmd.CommandLine = {"clang++", "-resource-dir", testPath("true/resources"),
"foo.cc"};
Mangler(Cmd, "foo.cc");
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
HasSubstr("-resource-dir " + testPath("true/resources")));
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
Not(HasSubstr(testPath("fake/resources"))));
}

{
tooling::CompileCommand Cmd;
Cmd.CommandLine = {"clang++", "-resource-dir=" + testPath("true/resources"),
"foo.cc"};
Mangler(Cmd, "foo.cc");
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
HasSubstr("-resource-dir=" + testPath("true/resources")));
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
Not(HasSubstr(testPath("fake/resources"))));
}
}

TEST(CommandMangler, RespectsOriginalSysroot) {
auto Mangler = CommandMangler::forTests();
Mangler.Sysroot = testPath("fake/sysroot");

{
tooling::CompileCommand Cmd;
Cmd.CommandLine = {"clang++", "-isysroot", testPath("true/sysroot"),
"foo.cc"};
Mangler(Cmd, "foo.cc");
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
HasSubstr("-isysroot " + testPath("true/sysroot")));
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
Not(HasSubstr(testPath("fake/sysroot"))));
}

{
tooling::CompileCommand Cmd;
Cmd.CommandLine = {"clang++", "-isysroot" + testPath("true/sysroot"),
"foo.cc"};
Mangler(Cmd, "foo.cc");
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
HasSubstr("-isysroot" + testPath("true/sysroot")));
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
Not(HasSubstr(testPath("fake/sysroot"))));
}

{
tooling::CompileCommand Cmd;
Cmd.CommandLine = {"clang++", "--sysroot", testPath("true/sysroot"),
"foo.cc"};
Mangler(Cmd, "foo.cc");
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
HasSubstr("--sysroot " + testPath("true/sysroot")));
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
Not(HasSubstr(testPath("fake/sysroot"))));
}

{
tooling::CompileCommand Cmd;
Cmd.CommandLine = {"clang++", "--sysroot=" + testPath("true/sysroot"),
"foo.cc"};
Mangler(Cmd, "foo.cc");
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
HasSubstr("--sysroot=" + testPath("true/sysroot")));
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
Not(HasSubstr(testPath("fake/sysroot"))));
}
}
} // namespace
} // namespace clangd
} // namespace clang
6 changes: 5 additions & 1 deletion clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Improvements to clang-tidy

- Improved `--dump-config` to print check options in alphabetical order.

- Improved :program:`clang-tidy-diff.py` script.
- Improved :program:`clang-tidy-diff.py` script.
* Return exit code `1` if any :program:`clang-tidy` subprocess exits with
a non-zero code or if exporting fixes fails.

Expand Down Expand Up @@ -381,6 +381,10 @@ Changes in existing checks
<clang-tidy/checks/misc/redundant-expression>` check to ignore
false-positives in unevaluated context (e.g., ``decltype``).

- Improved :doc:`misc-static-assert
<clang-tidy/checks/misc/static-assert>` check to ignore false-positives when
referring to non-``constexpr`` variables in non-unevaluated context.

- Improved :doc:`misc-unused-using-decls
<clang-tidy/checks/misc/unused-using-decls>` check to avoid false positive when
using in elaborated type and only check cpp files.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This check implements detection of local variables which could be declared as
coding guidelines, such as:
`ES.25 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es25-declare-an-object-const-or-constexpr-unless-you-want-to-modify-its-value-later-on>`_
from the C++ Core Guidelines and `AUTOSAR C++14 Rule A7-1-1 (6.7.1 Specifiers)
<https://www.autosar.org/fileadmin/user_upload/standards/adaptive/17-03/AUTOSAR_RS_CPP14Guidelines.pdf>`_.
<https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf>`_.

Please note that this check's analysis is type-based only. Variables that are not modified
but used to create a non-const handle that might escape the scope are not diagnosed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ types and definitions with good return type but wrong ``return`` statements.
type (e.g. ``int``).
* Private and deleted operators are ignored.
* The operator must always return ``*this``.

This check implements `AUTOSAR C++14 Rule A13-2-1
<https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf>`_.
42 changes: 42 additions & 0 deletions clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,48 @@ void print(...);
#define my_macro() assert(0 == 1)
// CHECK-FIXES: #define my_macro() assert(0 == 1)

namespace PR24066 {

void referenceMember() {
struct {
int A;
int B;
} S;
assert(&S.B - &S.A == 1);
}

const int X = 1;
void referenceVariable() {
assert(X > 0);
}


constexpr int Y = 1;
void referenceConstexprVariable() {
assert(Y > 0);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be replaced by static_assert() [misc-static-assert]
// CHECK-FIXES-CXX11: {{^ }}static_assert(Y > 0, "");
// CHECK-FIXES-CXX17: {{^ }}static_assert(Y > 0);
}

void useInSizeOf() {
char a = 0;
assert(sizeof(a) == 1U);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be replaced by static_assert() [misc-static-assert]
// CHECK-FIXES-CXX11: {{^ }}static_assert(sizeof(a) == 1U, "");
// CHECK-FIXES-CXX17: {{^ }}static_assert(sizeof(a) == 1U);
}

void useInDecltype() {
char a = 0;
assert(static_cast<decltype(a)>(256) == 0);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be replaced by static_assert() [misc-static-assert]
// CHECK-FIXES-CXX11: {{^ }}static_assert(static_cast<decltype(a)>(256) == 0, "");
// CHECK-FIXES-CXX17: {{^ }}static_assert(static_cast<decltype(a)>(256) == 0);
}

}

constexpr bool myfunc(int a, int b) { return a * b == 0; }

typedef __SIZE_TYPE__ size_t;
Expand Down
2 changes: 1 addition & 1 deletion clang/.clang-tidy
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Note that the readability-identifier-naming check is disabled, there are too
# many violations in the codebase and they create too much noise in clang-tidy
# results.
Checks: '-readability-identifier-naming, -misc-include*'
Checks: '-readability-identifier-naming'
InheritParentConfig: true
16 changes: 16 additions & 0 deletions clang/cmake/caches/Fuchsia.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,25 @@ set(_FUCHSIA_BOOTSTRAP_PASSTHROUGH
CURL_ROOT
OpenSSL_ROOT
httplib_ROOT

# Deprecated
CursesAndPanel_ROOT

CURSES_INCLUDE_DIRS
CURSES_LIBRARIES
PANEL_LIBRARIES

# Deprecated
Terminfo_ROOT

Terminfo_LIBRARIES

# Deprecated
LibEdit_ROOT

LibEdit_INCLUDE_DIRS
LibEdit_LIBRARIES

FUCHSIA_ENABLE_LLDB
LLDB_ENABLE_CURSES
LLDB_ENABLE_LIBEDIT
Expand Down
13 changes: 12 additions & 1 deletion clang/cmake/caches/Release.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
# BOOTSTRAP_* options configure the second build.
# BOOTSTRAP_BOOTSTRAP_* options configure the third build.

# General Options
set(LLVM_RELEASE_ENABLE_LTO THIN CACHE STRING "")

set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")

# Stage 1 Bootstrap Setup
Expand Down Expand Up @@ -33,9 +36,17 @@ set(BOOTSTRAP_CLANG_BOOTSTRAP_TARGETS
check-clang CACHE STRING "")

# Stage 2 Options
set(BOOTSTRAP_LLVM_ENABLE_PROJECTS "clang" CACHE STRING "")
set(STAGE2_PROJECTS "clang")
if (LLVM_RELEASE_ENABLE_LTO)
list(APPEND STAGE2_PROJECTS "lld")
endif()
set(BOOTSTRAP_LLVM_ENABLE_PROJECTS ${STAGE2_PROJECTS} CACHE STRING "")
set(BOOTSTRAP_LLVM_TARGETS_TO_BUILD Native CACHE STRING "")

# Stage 3 Options
set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "")
set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_PROJECTS "clang;lld;lldb;clang-tools-extra;bolt;polly;mlir;flang" CACHE STRING "")
set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LTO ${LLVM_RELEASE_ENABLE_LTO} CACHE STRING "")
if (LLVM_RELEASE_ENABLE_LTO)
set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LLD ON CACHE BOOL "")
endif()
2 changes: 1 addition & 1 deletion clang/docs/HLSL/FunctionCalls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ undefined behavior in HLSL, and any use of the argument after the call is a use
of an undefined value which may be illegal in the target (DXIL programs with
used or potentially used ``undef`` or ``poison`` values fail validation).

Clang Implementation
Clang Implementation
====================

.. note::
Expand Down
2 changes: 1 addition & 1 deletion clang/docs/InternalsManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ the option appears on the command line, the argument value is simply copied.
.. code-block:: text
def isysroot : JoinedOrSeparate<["-"], "isysroot">,
Visibility<[ClangOption, CC1Option]>,
Visibility<[ClangOption, CC1Option, FlangOption]>,
MarshallingInfoString<HeaderSearchOpts<"Sysroot">, [{"/"}]>;
**List of Strings**
Expand Down
31 changes: 31 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,29 @@ These changes are ones which we think may surprise users when upgrading to
Clang |release| because of the opportunity they pose for disruption to existing
code bases.

- Fix a bug in reversed argument for templated operators.
This breaks code in C++20 which was previously accepted in C++17.
Clang did not properly diagnose such casese in C++20 before this change. Eg:

.. code-block:: cpp
struct P {};
template<class S> bool operator==(const P&, const S&);
struct A : public P {};
struct B : public P {};
// This equality is now ambiguous in C++20.
bool ambiguous(A a, B b) { return a == b; }
template<class S> bool operator!=(const P&, const S&);
// Ok. Found a matching operator!=.
bool fine(A a, B b) { return a == b; }
To reduce such widespread breakages, as an extension, Clang accepts this code
with an existing warning ``-Wambiguous-reversed-operator`` warning.
Fixes `GH <https://github.com/llvm/llvm-project/issues/53954>`_.

- The CMake variable ``GCC_INSTALL_PREFIX`` (which sets the default
``--gcc-toolchain=``) is deprecated and will be removed. Specify
``--gcc-install-dir=`` or ``--gcc-triple=`` in a `configuration file
Expand Down Expand Up @@ -74,6 +97,10 @@ C/C++ Language Potentially Breaking Changes
outlined in "The Equality Operator You Are Looking For" (`P2468 <http://wg21.link/p2468r2>`_).
Fixes (`#68901: <https://github.com/llvm/llvm-project/issues/68901>`_).

- Remove the hardcoded path to the imported modules for C++20 named modules. Now we
require all the dependent modules to specified from the command line.
See (`#62707: <https://github.com/llvm/llvm-project/issues/62707>`_).

C++ Specific Potentially Breaking Changes
-----------------------------------------
- The name mangling rules for function templates has been changed to take into
Expand Down Expand Up @@ -719,6 +746,10 @@ Bug Fixes in This Version
- Clang now emits correct source location for code-coverage regions in `if constexpr`
and `if consteval` branches.
Fixes (`#54419 <https://github.com/llvm/llvm-project/issues/54419>`_)
- Fix assertion failure when declaring a template friend function with
a constrained parameter in a template class that declares a class method
or lambda at different depth.
Fixes (`#75426 <https://github.com/llvm/llvm-project/issues/75426>`_)
- Fix an issue where clang cannot find conversion function with template
parameter when instantiation of template class.
Fixes (`#77583 <https://github.com/llvm/llvm-project/issues/77583>`_)
Expand Down
11 changes: 5 additions & 6 deletions clang/docs/StandardCPlusPlusModules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ Then we type:
.. code-block:: console
$ clang++ -std=c++20 Hello.cppm --precompile -o Hello.pcm
$ clang++ -std=c++20 use.cpp -fprebuilt-module-path=. Hello.pcm -o Hello.out
$ clang++ -std=c++20 use.cpp -fmodule-file=Hello=Hello.pcm Hello.pcm -o Hello.out
$ ./Hello.out
Hello World!
Expand Down Expand Up @@ -200,15 +200,15 @@ Then we are able to compile the example by the following command:
$ clang++ -std=c++20 interface_part.cppm --precompile -o M-interface_part.pcm
$ clang++ -std=c++20 impl_part.cppm --precompile -fprebuilt-module-path=. -o M-impl_part.pcm
$ clang++ -std=c++20 M.cppm --precompile -fprebuilt-module-path=. -o M.pcm
$ clang++ -std=c++20 Impl.cpp -fmodule-file=M=M.pcm -c -o Impl.o
$ clang++ -std=c++20 Impl.cpp -fprebuilt-module-path=. -c -o Impl.o
# Compiling the user
$ clang++ -std=c++20 User.cpp -fprebuilt-module-path=. -c -o User.o
# Compiling the module and linking it together
$ clang++ -std=c++20 M-interface_part.pcm -c -o M-interface_part.o
$ clang++ -std=c++20 M-impl_part.pcm -c -o M-impl_part.o
$ clang++ -std=c++20 M.pcm -c -o M.o
$ clang++ -std=c++20 M-interface_part.pcm -fprebuilt-module-path=. -c -o M-interface_part.o
$ clang++ -std=c++20 M-impl_part.pcm -fprebuilt-module-path=. -c -o M-impl_part.o
$ clang++ -std=c++20 M.pcm -fprebuilt-module-path=. -c -o M.o
$ clang++ User.o M-interface_part.o M-impl_part.o M.o Impl.o -o a.out
We explain the options in the following sections.
Expand All @@ -218,7 +218,6 @@ How to enable standard C++ modules

Currently, standard C++ modules are enabled automatically
if the language standard is ``-std=c++20`` or newer.
The ``-fmodules-ts`` option is deprecated and is planned to be removed.

How to produce a BMI
~~~~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ def warn_unsupported_branch_protection: Warning <
def err_sls_hardening_arm_not_supported : Error<
"-mharden-sls is only supported on armv7-a or later">;
def warn_drv_large_data_threshold_invalid_code_model: Warning<
"'%0' only applies to medium code model">,
"'%0' only applies to medium and large code models">,
InGroup<UnusedCommandLineArgument>;

def note_drv_command_failed_diag_msg : Note<
Expand Down
6 changes: 2 additions & 4 deletions clang/include/clang/Basic/DiagnosticSerializationKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,8 @@ def warn_module_system_bit_conflict : Warning<
"as a non-system module; any difference in diagnostic options will be ignored">,
InGroup<ModuleConflict>;

def warn_reading_std_cxx_module_by_implicit_paths : Warning<
"it is deprecated to read module '%0' implicitly; it is going to be removed in clang 18; "
"consider to specify the dependencies explicitly">,
InGroup<DiagGroup<"read-modules-implicitly">>;
def err_failed_to_find_module_file : Error<
"failed to find module file for module '%0'">;
} // let CategoryName

let CategoryName = "AST Serialization Issue" in {
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ ENUM_LANGOPT(SignReturnAddressKey, SignReturnAddressKeyKind, 1, SignReturnAddres
"Key used for return address signing")
LANGOPT(BranchTargetEnforcement, 1, 0, "Branch-target enforcement enabled")
LANGOPT(BranchProtectionPAuthLR, 1, 0, "Use PC as a diversifier using PAuthLR NOP instructions.")
LANGOPT(GuardedControlStack, 1, 0, "Guarded control stack enabled")

LANGOPT(SpeculativeLoadHardening, 1, 0, "Speculative load hardening enabled")

Expand Down
36 changes: 36 additions & 0 deletions clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,42 @@ enum class OpenACCClauseKind {
If,
/// 'self' clause, allowed on Compute and Combined Constructs, plus 'update'.
Self,
/// 'copy' clause, allowed on Compute and Combined Constructs, plus 'data' and
/// 'declare'.
Copy,
/// 'use_device' clause, allowed on 'host_data' construct.
UseDevice,
/// 'attach' clause, allowed on Compute and Combined constructs, plus 'data'
/// and 'enter data'.
Attach,
/// 'delete' clause, allowed on the 'exit data' construct.
Delete,
/// 'detach' clause, allowed on the 'exit data' construct.
Detach,
/// 'device' clause, allowed on the 'update' construct.
Device,
/// 'deviceptr' clause, allowed on Compute and Combined Constructs, plus
/// 'data' and 'declare'.
DevicePtr,
/// 'device_resident' clause, allowed on the 'declare' construct.
DeviceResident,
/// 'firstprivate' clause, allowed on 'parallel', 'serial', 'parallel loop',
/// and 'serial loop' constructs.
FirstPrivate,
/// 'host' clause, allowed on 'update' construct.
Host,
/// 'link' clause, allowed on 'declare' construct.
Link,
/// 'no_create' clause, allowed on allowed on Compute and Combined constructs,
/// plus 'data'.
NoCreate,
/// 'present' clause, allowed on Compute and Combined constructs, plus 'data'
/// and 'declare'.
Present,
/// 'private' clause, allowed on 'parallel', 'serial', 'loop', 'parallel
/// loop', and 'serial loop' constructs.
Private,

/// Represents an invalid clause, for the purposes of parsing.
Invalid,
};
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1373,6 +1373,7 @@ class TargetInfo : public TransferrableTargetInfo,
LangOptions::SignReturnAddressKeyKind::AKey;
bool BranchTargetEnforcement = false;
bool BranchProtectionPAuthLR = false;
bool GuardedControlStack = false;
};

/// Determine if the Architecture in this TargetInfo supports branch
Expand Down
18 changes: 9 additions & 9 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -2238,15 +2238,15 @@ let TargetGuard = "sme2" in {
def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
def SVCVT_BF16_X2 : SInst<"svcvt_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvt_x2", [IsOverloadNone, IsStreaming],[]>;

def SVCVT_F32_U32_X2 : SInst<"svcvt_{d}[_u32_x2]", "2.d2.u", "f", MergeNone, "aarch64_sve_fcvtu_x2", [IsStreaming], []>;
def SVCVT_U32_F32_X2 : SInst<"svcvt_u32[_{d}_x2]", "2.u2.d", "f", MergeNone, "aarch64_sve_ucvtf_x2", [IsStreaming], []>;
def SVCVT_F32_S32_X2 : SInst<"svcvt_{d}[_s32_x2]", "2.d2.x", "f", MergeNone, "aarch64_sve_fcvts_x2", [IsStreaming], []>;
def SVCVT_S32_F32_X2 : SInst<"svcvt_s32[_{d}_x2]", "2.x2.d", "f", MergeNone, "aarch64_sve_scvtf_x2", [IsStreaming], []>;

def SVCVT_F32_U32_X4 : SInst<"svcvt_{d}[_u32_x4]", "4.d4.u", "f", MergeNone, "aarch64_sve_fcvtu_x4", [IsStreaming], []>;
def SVCVT_U32_F32_X4 : SInst<"svcvt_u32[_{d}_x4]", "4.u4.d", "f", MergeNone, "aarch64_sve_ucvtf_x4", [IsStreaming], []>;
def SVCVT_F32_S32_X4 : SInst<"svcvt_{d}[_s32_x4]", "4.d4.x", "f", MergeNone, "aarch64_sve_fcvts_x4", [IsStreaming], []>;
def SVCVT_S32_F32_X4 : SInst<"svcvt_s32[_{d}_x4]", "4.x4.d", "f", MergeNone, "aarch64_sve_scvtf_x4", [IsStreaming], []>;
def SVCVT_F32_U32_X2 : SInst<"svcvt_{d}[_u32_x2]", "2.d2.u", "f", MergeNone, "aarch64_sve_ucvtf_x2", [IsStreaming], []>;
def SVCVT_U32_F32_X2 : SInst<"svcvt_u32[_{d}_x2]", "2.u2.d", "f", MergeNone, "aarch64_sve_fcvtu_x2", [IsStreaming], []>;
def SVCVT_F32_S32_X2 : SInst<"svcvt_{d}[_s32_x2]", "2.d2.x", "f", MergeNone, "aarch64_sve_scvtf_x2", [IsStreaming], []>;
def SVCVT_S32_F32_X2 : SInst<"svcvt_s32[_{d}_x2]", "2.x2.d", "f", MergeNone, "aarch64_sve_fcvts_x2", [IsStreaming], []>;

def SVCVT_F32_U32_X4 : SInst<"svcvt_{d}[_u32_x4]", "4.d4.u", "f", MergeNone, "aarch64_sve_ucvtf_x4", [IsStreaming], []>;
def SVCVT_U32_F32_X4 : SInst<"svcvt_u32[_{d}_x4]", "4.u4.d", "f", MergeNone, "aarch64_sve_fcvtu_x4", [IsStreaming], []>;
def SVCVT_F32_S32_X4 : SInst<"svcvt_{d}[_s32_x4]", "4.d4.x", "f", MergeNone, "aarch64_sve_scvtf_x4", [IsStreaming], []>;
def SVCVT_S32_F32_X4 : SInst<"svcvt_s32[_{d}_x4]", "4.x4.d", "f", MergeNone, "aarch64_sve_fcvts_x4", [IsStreaming], []>;
}

//
Expand Down
8 changes: 5 additions & 3 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4267,7 +4267,7 @@ def iquote : JoinedOrSeparate<["-"], "iquote">, Group<clang_i_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Add directory to QUOTE include search path">, MetaVarName<"<directory>">;
def isysroot : JoinedOrSeparate<["-"], "isysroot">, Group<clang_i_Group>,
Visibility<[ClangOption, CC1Option]>,
Visibility<[ClangOption, CC1Option, FlangOption]>,
HelpText<"Set the system root directory (usually /)">, MetaVarName<"<dir>">,
MarshallingInfoString<HeaderSearchOpts<"Sysroot">, [{"/"}]>;
def isystem : JoinedOrSeparate<["-"], "isystem">, Group<clang_i_Group>,
Expand Down Expand Up @@ -4392,8 +4392,8 @@ def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoString<TargetOpts<"CodeModel">, [{"default"}]>;
def mlarge_data_threshold_EQ : Joined<["-"], "mlarge-data-threshold=">, Group<m_Group>,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoInt<TargetOpts<"LargeDataThreshold">, "65535">;
Flags<[TargetSpecific]>, Visibility<[ClangOption, CC1Option]>,
MarshallingInfoInt<TargetOpts<"LargeDataThreshold">, "0">;
def mtls_size_EQ : Joined<["-"], "mtls-size=">, Group<m_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Specify bit size of immediate TLS offsets (AArch64 ELF only): "
Expand Down Expand Up @@ -7012,6 +7012,8 @@ def mbranch_target_enforce : Flag<["-"], "mbranch-target-enforce">,
MarshallingInfoFlag<LangOpts<"BranchTargetEnforcement">>;
def mbranch_protection_pauth_lr : Flag<["-"], "mbranch-protection-pauth-lr">,
MarshallingInfoFlag<LangOpts<"BranchProtectionPAuthLR">>;
def mguarded_control_stack : Flag<["-"], "mguarded-control-stack">,
MarshallingInfoFlag<LangOpts<"GuardedControlStack">>;
def fno_dllexport_inlines : Flag<["-"], "fno-dllexport-inlines">,
MarshallingInfoNegativeFlag<LangOpts<"DllExportInlines">>;
def cfguard_no_checks : Flag<["-"], "cfguard-no-checks">,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3055,6 +3055,7 @@ struct FormatStyle {
bool isProto() const {
return Language == LK_Proto || Language == LK_TextProto;
}
bool isTableGen() const { return Language == LK_TableGen; }

/// Language, this format style is targeted at.
/// \version 3.5
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_PARSE_PARSER_H
#define LLVM_CLANG_PARSE_PARSER_H

#include "clang/Basic/OpenACCKinds.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/Preprocessor.h"
Expand Down Expand Up @@ -3568,6 +3569,16 @@ class Parser : public CodeCompletionHandler {
void ParseOpenACCCacheVarList();
/// Parses a single variable in a variable list for OpenACC.
bool ParseOpenACCVar();
/// Parses the variable list for the variety of clauses that take a var-list,
/// including the optional Special Token listed for some,based on clause type.
bool ParseOpenACCClauseVarList(OpenACCClauseKind Kind);
/// Parses any parameters for an OpenACC Clause, including required/optional
/// parens.
bool ParseOpenACCClauseParams(OpenACCClauseKind Kind);
/// Parses a single clause in a clause-list for OpenACC.
bool ParseOpenACCClause();
/// Parses the clause-list for an OpenACC directive.
void ParseOpenACCClauseList();
bool ParseOpenACCWaitArgument();

private:
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,

BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement;
BPI.BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
BPI.GuardedControlStack = PBP.GuardedControlStack;
return true;
}

Expand Down Expand Up @@ -532,6 +533,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (Opts.BranchTargetEnforcement)
Builder.defineMacro("__ARM_FEATURE_BTI_DEFAULT", "1");

if (Opts.GuardedControlStack)
Builder.defineMacro("__ARM_FEATURE_GCS_DEFAULT", "1");

if (HasLS64)
Builder.defineMacro("__ARM_FEATURE_LS64", "1");

Expand All @@ -544,6 +548,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasD128)
Builder.defineMacro("__ARM_FEATURE_SYSREG128", "1");

if (HasGCS)
Builder.defineMacro("__ARM_FEATURE_GCS", "1");

if (*ArchInfo == llvm::AArch64::ARMV8_1A)
getTargetDefinesARMV81A(Opts, Builder);
else if (*ArchInfo == llvm::AArch64::ARMV8_2A)
Expand Down
30 changes: 17 additions & 13 deletions clang/lib/CodeGen/CGObjCGNU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1431,12 +1431,24 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
const std::string &TypeEncoding) override {
return GetConstantSelector(Sel, TypeEncoding);
}
std::string GetSymbolNameForTypeEncoding(const std::string &TypeEncoding) {
std::string MangledTypes = std::string(TypeEncoding);
// @ is used as a special character in ELF symbol names (used for symbol
// versioning), so mangle the name to not include it. Replace it with a
// character that is not a valid type encoding character (and, being
// non-printable, never will be!)
if (CGM.getTriple().isOSBinFormatELF())
std::replace(MangledTypes.begin(), MangledTypes.end(), '@', '\1');
// = in dll exported names causes lld to fail when linking on Windows.
if (CGM.getTriple().isOSWindows())
std::replace(MangledTypes.begin(), MangledTypes.end(), '=', '\2');
return MangledTypes;
}
llvm::Constant *GetTypeString(llvm::StringRef TypeEncoding) {
if (TypeEncoding.empty())
return NULLPtr;
std::string MangledTypes = std::string(TypeEncoding);
std::replace(MangledTypes.begin(), MangledTypes.end(),
'@', '\1');
std::string MangledTypes =
GetSymbolNameForTypeEncoding(std::string(TypeEncoding));
std::string TypesVarName = ".objc_sel_types_" + MangledTypes;
auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName);
if (!TypesGlobal) {
Expand All @@ -1453,13 +1465,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
}
llvm::Constant *GetConstantSelector(Selector Sel,
const std::string &TypeEncoding) override {
// @ is used as a special character in symbol names (used for symbol
// versioning), so mangle the name to not include it. Replace it with a
// character that is not a valid type encoding character (and, being
// non-printable, never will be!)
std::string MangledTypes = TypeEncoding;
std::replace(MangledTypes.begin(), MangledTypes.end(),
'@', '\1');
std::string MangledTypes = GetSymbolNameForTypeEncoding(TypeEncoding);
auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" +
MangledTypes).str();
if (auto *GV = TheModule.getNamedGlobal(SelVarName))
Expand Down Expand Up @@ -1671,9 +1677,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
const ObjCIvarDecl *Ivar) override {
std::string TypeEncoding;
CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding);
// Prevent the @ from being interpreted as a symbol version.
std::replace(TypeEncoding.begin(), TypeEncoding.end(),
'@', '\1');
TypeEncoding = GetSymbolNameForTypeEncoding(TypeEncoding);
const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
+ '.' + Ivar->getNameAsString() + '.' + TypeEncoding;
return Name;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,8 @@ void CodeGenModule::Release() {
if (LangOpts.BranchProtectionPAuthLR)
getModule().addModuleFlag(llvm::Module::Min, "branch-protection-pauth-lr",
1);
if (LangOpts.GuardedControlStack)
getModule().addModuleFlag(llvm::Module::Min, "guarded-control-stack", 1);
if (LangOpts.hasSignReturnAddress())
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address", 1);
if (LangOpts.isSignReturnAddressScopeAll())
Expand Down Expand Up @@ -1199,7 +1201,7 @@ void CodeGenModule::Release() {
llvm::CodeModel::Model codeModel = static_cast<llvm::CodeModel::Model>(CM);
getModule().setCodeModel(codeModel);

if (CM == llvm::CodeModel::Medium &&
if ((CM == llvm::CodeModel::Medium || CM == llvm::CodeModel::Large) &&
Context.getTargetInfo().getTriple().getArch() ==
llvm::Triple::x86_64) {
getModule().setLargeDataThreshold(getCodeGenOpts().LargeDataThreshold);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
BPI.BranchTargetEnforcement ? "true" : "false");
Fn->addFnAttr("branch-protection-pauth-lr",
BPI.BranchProtectionPAuthLR ? "true" : "false");
Fn->addFnAttr("guarded-control-stack",
BPI.GuardedControlStack ? "true" : "false");
}

bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,
Expand Down
8 changes: 1 addition & 7 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr;
static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr;
static const SanitizerMask NotAllowedWithExecuteOnly =
SanitizerKind::Function | SanitizerKind::KCFI;
static const SanitizerMask RequiresPIE =
SanitizerKind::DataFlow | SanitizerKind::Scudo;
static const SanitizerMask NeedsUnwindTables =
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
SanitizerKind::Memory | SanitizerKind::DataFlow;
Expand Down Expand Up @@ -303,9 +301,7 @@ bool SanitizerArgs::needsCfiDiagRt() const {
CfiCrossDso && !ImplicitCfiRuntime;
}

bool SanitizerArgs::requiresPIE() const {
return NeedPIE || (Sanitizers.Mask & RequiresPIE);
}
bool SanitizerArgs::requiresPIE() const { return NeedPIE; }

bool SanitizerArgs::needsUnwindTables() const {
return static_cast<bool>(Sanitizers.Mask & NeedsUnwindTables);
Expand Down Expand Up @@ -699,8 +695,6 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
MsanParamRetval = Args.hasFlag(
options::OPT_fsanitize_memory_param_retval,
options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
NeedPIE |= !(TC.getTriple().isOSLinux() &&
TC.getTriple().getArch() == llvm::Triple::x86_64);
} else if (AllAddedKinds & SanitizerKind::KernelMemory) {
MsanUseAfterDtor = false;
MsanParamRetval = Args.hasFlag(
Expand Down
28 changes: 18 additions & 10 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1508,7 +1508,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< Triple.getArchName();

StringRef Scope, Key;
bool IndirectBranches, BranchProtectionPAuthLR;
bool IndirectBranches, BranchProtectionPAuthLR, GuardedControlStack;

if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
Scope = A->getValue();
Expand All @@ -1518,6 +1518,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
Key = "a_key";
IndirectBranches = false;
BranchProtectionPAuthLR = false;
GuardedControlStack = false;
} else {
StringRef DiagMsg;
llvm::ARM::ParsedBranchProtection PBP;
Expand All @@ -1531,6 +1532,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
Key = PBP.Key;
BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
IndirectBranches = PBP.BranchTargetEnforcement;
GuardedControlStack = PBP.GuardedControlStack;
}

CmdArgs.push_back(
Expand All @@ -1543,6 +1545,8 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
Args.MakeArgString(Twine("-mbranch-protection-pauth-lr")));
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
if (GuardedControlStack)
CmdArgs.push_back("-mguarded-control-stack");
}

void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
Expand Down Expand Up @@ -5748,20 +5752,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}

if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) {
if (!Triple.isX86()) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getOption().getName() << TripleStr;
} else {
bool IsMediumCM = false;
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ))
IsMediumCM = StringRef(A->getValue()) == "medium";
if (!IsMediumCM) {
if (Triple.getArch() == llvm::Triple::x86_64) {
bool IsMediumCM = false;
bool IsLargeCM = false;
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
IsMediumCM = StringRef(A->getValue()) == "medium";
IsLargeCM = StringRef(A->getValue()) == "large";
}
if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) {
if (!IsMediumCM && !IsLargeCM) {
D.Diag(diag::warn_drv_large_data_threshold_invalid_code_model)
<< A->getOption().getRenderName();
} else {
A->render(Args, CmdArgs);
}
} else if (IsMediumCM) {
CmdArgs.push_back("-mlarge-data-threshold=65536");
} else if (IsLargeCM) {
CmdArgs.push_back("-mlarge-data-threshold=0");
}
}

Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
const bool IsAMDGCN = ToolChain.getTriple().isAMDGCN();
const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath());
const Driver &D = ToolChain.getDriver();
const bool IsFatLTO = Args.hasArg(options::OPT_ffat_lto_objects);
const bool IsUnifiedLTO = Args.hasArg(options::OPT_funified_lto);
if (llvm::sys::path::filename(Linker) != "ld.lld" &&
llvm::sys::path::stem(Linker) != "ld.lld" &&
!ToolChain.getTriple().isOSOpenBSD()) {
Expand Down Expand Up @@ -765,7 +767,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
} else {
// Tell LLD to find and use .llvm.lto section in regular relocatable object
// files
if (Args.hasArg(options::OPT_ffat_lto_objects))
if (IsFatLTO)
CmdArgs.push_back("--fat-lto-objects");
}

Expand Down Expand Up @@ -825,7 +827,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
// Matrix intrinsic lowering happens at link time with ThinLTO. Enable
// LowerMatrixIntrinsicsPass, which is transitively called by
// buildThinLTODefaultPipeline under EnableMatrix.
if (IsThinLTO && Args.hasArg(options::OPT_fenable_matrix))
if ((IsThinLTO || IsFatLTO || IsUnifiedLTO) &&
Args.hasArg(options::OPT_fenable_matrix))
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-enable-matrix"));

Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,12 +403,10 @@ void Flang::addTargetOptions(const ArgList &Args,
if (A->getValue() == StringRef{"Accelerate"}) {
CmdArgs.push_back("-framework");
CmdArgs.push_back("Accelerate");
A->render(Args, CmdArgs);
}
}
} else {
A->render(Args, CmdArgs);
}
A->render(Args, CmdArgs);
}

if (Triple.isKnownWindowsMSVCEnvironment()) {
Expand Down
100 changes: 92 additions & 8 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,14 +275,15 @@ class AnnotatedLine;
struct FormatToken {
FormatToken()
: HasUnescapedNewline(false), IsMultiline(false), IsFirst(false),
MustBreakBefore(false), IsUnterminatedLiteral(false),
CanBreakBefore(false), ClosesTemplateDeclaration(false),
StartsBinaryExpression(false), EndsBinaryExpression(false),
PartOfMultiVariableDeclStmt(false), ContinuesLineCommentSection(false),
Finalized(false), ClosesRequiresClause(false),
EndsCppAttributeGroup(false), BlockKind(BK_Unknown),
Decision(FD_Unformatted), PackingKind(PPK_Inconclusive),
TypeIsFinalized(false), Type(TT_Unknown) {}
MustBreakBefore(false), MustBreakBeforeFinalized(false),
IsUnterminatedLiteral(false), CanBreakBefore(false),
ClosesTemplateDeclaration(false), StartsBinaryExpression(false),
EndsBinaryExpression(false), PartOfMultiVariableDeclStmt(false),
ContinuesLineCommentSection(false), Finalized(false),
ClosesRequiresClause(false), EndsCppAttributeGroup(false),
BlockKind(BK_Unknown), Decision(FD_Unformatted),
PackingKind(PPK_Inconclusive), TypeIsFinalized(false),
Type(TT_Unknown) {}

/// The \c Token.
Token Tok;
Expand Down Expand Up @@ -318,6 +319,10 @@ struct FormatToken {
/// before the token.
unsigned MustBreakBefore : 1;

/// Whether MustBreakBefore is finalized during parsing and must not
/// be reset between runs.
unsigned MustBreakBeforeFinalized : 1;

/// Set to \c true if this token is an unterminated literal.
unsigned IsUnterminatedLiteral : 1;

Expand Down Expand Up @@ -416,10 +421,14 @@ struct FormatToken {
/// to another one please use overwriteFixedType, or even better remove the
/// need to reassign the type.
void setFinalizedType(TokenType T) {
if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg)
return;
Type = T;
TypeIsFinalized = true;
}
void overwriteFixedType(TokenType T) {
if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg)
return;
TypeIsFinalized = false;
setType(T);
}
Expand Down Expand Up @@ -1202,6 +1211,21 @@ struct AdditionalKeywords {
kw_verilogHashHash = &IdentTable.get("##");
kw_apostrophe = &IdentTable.get("\'");

// TableGen keywords
kw_bit = &IdentTable.get("bit");
kw_bits = &IdentTable.get("bits");
kw_code = &IdentTable.get("code");
kw_dag = &IdentTable.get("dag");
kw_def = &IdentTable.get("def");
kw_defm = &IdentTable.get("defm");
kw_defset = &IdentTable.get("defset");
kw_defvar = &IdentTable.get("defvar");
kw_dump = &IdentTable.get("dump");
kw_include = &IdentTable.get("include");
kw_list = &IdentTable.get("list");
kw_multiclass = &IdentTable.get("multiclass");
kw_then = &IdentTable.get("then");

// Keep this at the end of the constructor to make sure everything here
// is
// already initialized.
Expand Down Expand Up @@ -1294,6 +1318,27 @@ struct AdditionalKeywords {
kw_wildcard, kw_wire,
kw_with, kw_wor,
kw_verilogHash, kw_verilogHashHash});

TableGenExtraKeywords = std::unordered_set<IdentifierInfo *>({
kw_assert,
kw_bit,
kw_bits,
kw_code,
kw_dag,
kw_def,
kw_defm,
kw_defset,
kw_defvar,
kw_dump,
kw_foreach,
kw_in,
kw_include,
kw_let,
kw_list,
kw_multiclass,
kw_string,
kw_then,
});
}

// Context sensitive keywords.
Expand Down Expand Up @@ -1539,6 +1584,21 @@ struct AdditionalKeywords {
// Symbols in Verilog that don't exist in C++.
IdentifierInfo *kw_apostrophe;

// TableGen keywords
IdentifierInfo *kw_bit;
IdentifierInfo *kw_bits;
IdentifierInfo *kw_code;
IdentifierInfo *kw_dag;
IdentifierInfo *kw_def;
IdentifierInfo *kw_defm;
IdentifierInfo *kw_defset;
IdentifierInfo *kw_defvar;
IdentifierInfo *kw_dump;
IdentifierInfo *kw_include;
IdentifierInfo *kw_list;
IdentifierInfo *kw_multiclass;
IdentifierInfo *kw_then;

/// Returns \c true if \p Tok is a keyword or an identifier.
bool isWordLike(const FormatToken &Tok) const {
// getIdentifierinfo returns non-null for keywords as well as identifiers.
Expand Down Expand Up @@ -1811,6 +1871,27 @@ struct AdditionalKeywords {
}
}

bool isTableGenDefinition(const FormatToken &Tok) const {
return Tok.isOneOf(kw_def, kw_defm, kw_defset, kw_defvar, kw_multiclass,
kw_let, tok::kw_class);
}

bool isTableGenKeyword(const FormatToken &Tok) const {
switch (Tok.Tok.getKind()) {
case tok::kw_class:
case tok::kw_else:
case tok::kw_false:
case tok::kw_if:
case tok::kw_int:
case tok::kw_true:
return true;
default:
return Tok.is(tok::identifier) &&
TableGenExtraKeywords.find(Tok.Tok.getIdentifierInfo()) !=
TableGenExtraKeywords.end();
}
}

private:
/// The JavaScript keywords beyond the C++ keyword set.
std::unordered_set<IdentifierInfo *> JsExtraKeywords;
Expand All @@ -1820,6 +1901,9 @@ struct AdditionalKeywords {

/// The Verilog keywords beyond the C++ keyword set.
std::unordered_set<IdentifierInfo *> VerilogExtraKeywords;

/// The TableGen keywords beyond the C++ keyword set.
std::unordered_set<IdentifierInfo *> TableGenExtraKeywords;
};

inline bool isLineComment(const FormatToken &FormatTok) {
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,9 @@ FormatToken *FormatTokenLexer::getNextToken() {
tok::kw_operator)) {
FormatTok->Tok.setKind(tok::identifier);
FormatTok->Tok.setIdentifierInfo(nullptr);
} else if (Style.isTableGen() && !Keywords.isTableGenKeyword(*FormatTok)) {
FormatTok->Tok.setKind(tok::identifier);
FormatTok->Tok.setIdentifierInfo(nullptr);
}
} else if (FormatTok->is(tok::greatergreater)) {
FormatTok->Tok.setKind(tok::greater);
Expand Down
26 changes: 18 additions & 8 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2234,6 +2234,12 @@ class AnnotatingParser {
if (PreviousNotConst->ClosesRequiresClause)
return false;

if (Style.isTableGen()) {
// keywords such as let and def* defines names.
if (Keywords.isTableGenDefinition(*PreviousNotConst))
return true;
}

bool IsPPKeyword = PreviousNotConst->is(tok::identifier) &&
PreviousNotConst->Previous &&
PreviousNotConst->Previous->is(tok::hash);
Expand Down Expand Up @@ -2369,7 +2375,7 @@ class AnnotatingParser {
}
}

if (Tok.Next->is(tok::question))
if (Tok.Next->isOneOf(tok::question, tok::ampamp))
return false;

// `foreach((A a, B b) in someList)` should not be seen as a cast.
Expand Down Expand Up @@ -2769,13 +2775,6 @@ class ExpressionParser {
// Consume operators with higher precedence.
parse(Precedence + 1);

// Do not assign fake parenthesis to tokens that are part of an
// unexpanded macro call. The line within the macro call contains
// the parenthesis and commas, and we will not find operators within
// that structure.
if (Current && Current->MacroParent)
break;

int CurrentPrecedence = getCurrentPrecedence();

if (Precedence == CurrentPrecedence && Current &&
Expand Down Expand Up @@ -2919,6 +2918,13 @@ class ExpressionParser {

void addFakeParenthesis(FormatToken *Start, prec::Level Precedence,
FormatToken *End = nullptr) {
// Do not assign fake parenthesis to tokens that are part of an
// unexpanded macro call. The line within the macro call contains
// the parenthesis and commas, and we will not find operators within
// that structure.
if (Start->MacroParent)
return;

Start->FakeLParens.push_back(Precedence);
if (Precedence > prec::Unknown)
Start->StartsBinaryExpression = true;
Expand Down Expand Up @@ -4668,6 +4674,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
} else if (Style.Language == FormatStyle::LK_Java) {
if (Left.is(tok::r_square) && Right.is(tok::l_brace))
return true;
// spaces inside square brackets.
if (Left.is(tok::l_square) || Right.is(tok::r_square))
return Style.SpacesInSquareBrackets;

if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren)) {
return Style.SpaceBeforeParensOptions.AfterControlStatements ||
spaceRequiredBeforeParens(Right);
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Format/UnwrappedLineFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,13 +954,15 @@ static void markFinalized(FormatToken *Tok) {
// will be modified as unexpanded arguments (as part of the macro call
// formatting) in the next pass.
Tok->MacroCtx->Role = MR_UnexpandedArg;
// Reset whether spaces are required before this token, as that is context
// dependent, and that context may change when formatting the macro call.
// For example, given M(x) -> 2 * x, and the macro call M(var),
// the token 'var' will have SpacesRequiredBefore = 1 after being
// Reset whether spaces or a line break are required before this token, as
// that is context dependent, and that context may change when formatting
// the macro call. For example, given M(x) -> 2 * x, and the macro call
// M(var), the token 'var' will have SpacesRequiredBefore = 1 after being
// formatted as part of the expanded macro, but SpacesRequiredBefore = 0
// for its position within the macro call.
Tok->SpacesRequiredBefore = 0;
if (!Tok->MustBreakBeforeFinalized)
Tok->MustBreakBefore = 0;
} else {
Tok->Finalized = true;
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4675,6 +4675,7 @@ void UnwrappedLineParser::readToken(int LevelDifference) {
conditionalCompilationEnd();
FormatTok = Tokens->getNextToken();
FormatTok->MustBreakBefore = true;
FormatTok->MustBreakBeforeFinalized = true;
}

auto IsFirstNonCommentOnLine = [](bool FirstNonCommentOnLine,
Expand Down Expand Up @@ -4891,6 +4892,7 @@ void UnwrappedLineParser::pushToken(FormatToken *Tok) {
Line->Tokens.push_back(UnwrappedLineNode(Tok));
if (MustBreakBeforeNextToken) {
Line->Tokens.back().Tok->MustBreakBefore = true;
Line->Tokens.back().Tok->MustBreakBeforeFinalized = true;
MustBreakBeforeNextToken = false;
}
}
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Format/WhitespaceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1451,8 +1451,10 @@ WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start,
} else if (C.Tok->is(tok::comma)) {
if (!Cells.empty())
Cells.back().EndIndex = i;
if (C.Tok->getNextNonComment()->isNot(tok::r_brace)) // dangling comma
if (const auto *Next = C.Tok->getNextNonComment();
Next && Next->isNot(tok::r_brace)) { // dangling comma
++Cell;
}
}
} else if (Depth == 1) {
if (C.Tok == MatchingParen) {
Expand Down
233 changes: 164 additions & 69 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,29 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) {

return llvm::StringSwitch<OpenACCClauseKind>(
Tok.getIdentifierInfo()->getName())
.Case("attach", OpenACCClauseKind::Attach)
.Case("auto", OpenACCClauseKind::Auto)
.Case("copy", OpenACCClauseKind::Copy)
.Case("default", OpenACCClauseKind::Default)
.Case("delete", OpenACCClauseKind::Delete)
.Case("detach", OpenACCClauseKind::Detach)
.Case("device", OpenACCClauseKind::Device)
.Case("device_resident", OpenACCClauseKind::DeviceResident)
.Case("deviceptr", OpenACCClauseKind::DevicePtr)
.Case("finalize", OpenACCClauseKind::Finalize)
.Case("firstprivate", OpenACCClauseKind::FirstPrivate)
.Case("host", OpenACCClauseKind::Host)
.Case("if", OpenACCClauseKind::If)
.Case("if_present", OpenACCClauseKind::IfPresent)
.Case("independent", OpenACCClauseKind::Independent)
.Case("link", OpenACCClauseKind::Link)
.Case("no_create", OpenACCClauseKind::NoCreate)
.Case("nohost", OpenACCClauseKind::NoHost)
.Case("present", OpenACCClauseKind::Present)
.Case("private", OpenACCClauseKind::Private)
.Case("self", OpenACCClauseKind::Self)
.Case("seq", OpenACCClauseKind::Seq)
.Case("use_device", OpenACCClauseKind::UseDevice)
.Case("vector", OpenACCClauseKind::Vector)
.Case("worker", OpenACCClauseKind::Worker)
.Default(OpenACCClauseKind::Invalid);
Expand Down Expand Up @@ -329,12 +343,55 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
return DirKind;
}

enum ClauseParensKind {
None,
Optional,
Required
};

ClauseParensKind getClauseParensKind(OpenACCClauseKind Kind) {
switch (Kind) {
case OpenACCClauseKind::Self:
return ClauseParensKind::Optional;

case OpenACCClauseKind::Default:
case OpenACCClauseKind::If:
case OpenACCClauseKind::Copy:
case OpenACCClauseKind::UseDevice:
case OpenACCClauseKind::NoCreate:
case OpenACCClauseKind::Present:
case OpenACCClauseKind::DevicePtr:
case OpenACCClauseKind::Attach:
case OpenACCClauseKind::Detach:
case OpenACCClauseKind::Private:
case OpenACCClauseKind::FirstPrivate:
case OpenACCClauseKind::Delete:
case OpenACCClauseKind::DeviceResident:
case OpenACCClauseKind::Device:
case OpenACCClauseKind::Link:
case OpenACCClauseKind::Host:
return ClauseParensKind::Required;

case OpenACCClauseKind::Auto:
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Independent:
case OpenACCClauseKind::Invalid:
case OpenACCClauseKind::NoHost:
case OpenACCClauseKind::Seq:
case OpenACCClauseKind::Worker:
case OpenACCClauseKind::Vector:
return ClauseParensKind::None;
}
llvm_unreachable("Unhandled clause kind");
}

bool ClauseHasOptionalParens(OpenACCClauseKind Kind) {
return Kind == OpenACCClauseKind::Self;
return getClauseParensKind(Kind) == ClauseParensKind::Optional;
}

bool ClauseHasRequiredParens(OpenACCClauseKind Kind) {
return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If;
return getClauseParensKind(Kind) == ClauseParensKind::Required;
}

ExprResult ParseOpenACCConditionalExpr(Parser &P) {
Expand All @@ -345,43 +402,137 @@ ExprResult ParseOpenACCConditionalExpr(Parser &P) {
return P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression());
}

bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
BalancedDelimiterTracker Parens(P, tok::l_paren,
// Skip until we see the end of pragma token, but don't consume it. This is us
// just giving up on the rest of the pragma so we can continue executing. We
// have to do this because 'SkipUntil' considers paren balancing, which isn't
// what we want.
void SkipUntilEndOfDirective(Parser &P) {
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
P.ConsumeAnyToken();
}

} // namespace

// OpenACC 3.3, section 1.7:
// To simplify the specification and convey appropriate constraint information,
// a pqr-list is a comma-separated list of pdr items. The one exception is a
// clause-list, which is a list of one or more clauses optionally separated by
// commas.
void Parser::ParseOpenACCClauseList() {
bool FirstClause = true;
while (getCurToken().isNot(tok::annot_pragma_openacc_end)) {
// Comma is optional in a clause-list.
if (!FirstClause && getCurToken().is(tok::comma))
ConsumeToken();
FirstClause = false;

// Recovering from a bad clause is really difficult, so we just give up on
// error.
if (ParseOpenACCClause()) {
SkipUntilEndOfDirective(*this);
return;
}
}
}

bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) {
// FIXME: Future clauses will require 'special word' parsing, check for one,
// then parse it based on whether it is a clause that requires a 'special
// word'.
(void)Kind;

// If the var parsing fails, skip until the end of the directive as this is
// an expression and gets messy if we try to continue otherwise.
if (ParseOpenACCVar())
return true;

while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
ExpectAndConsume(tok::comma);

// If the var parsing fails, skip until the end of the directive as this is
// an expression and gets messy if we try to continue otherwise.
if (ParseOpenACCVar())
return true;
}
return false;
}
// The OpenACC Clause List is a comma or space-delimited list of clauses (see
// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
// really have its owner grammar and each individual one has its own definition.
// However, they all are named with a single-identifier (or auto/default!)
// token, followed in some cases by either braces or parens.
bool Parser::ParseOpenACCClause() {
// A number of clause names are actually keywords, so accept a keyword that
// can be converted to a name.
if (expectIdentifierOrKeyword(*this))
return true;

OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken());

if (Kind == OpenACCClauseKind::Invalid)
return Diag(getCurToken(), diag::err_acc_invalid_clause)
<< getCurToken().getIdentifierInfo();

// Consume the clause name.
ConsumeToken();

return ParseOpenACCClauseParams(Kind);
}

bool Parser::ParseOpenACCClauseParams(OpenACCClauseKind Kind) {
BalancedDelimiterTracker Parens(*this, tok::l_paren,
tok::annot_pragma_openacc_end);

if (ClauseHasRequiredParens(Kind)) {
if (Parens.expectAndConsume()) {
// We are missing a paren, so assume that the person just forgot the
// parameter. Return 'false' so we try to continue on and parse the next
// clause.
P.SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return false;
}

switch (Kind) {
case OpenACCClauseKind::Default: {
Token DefKindTok = P.getCurToken();
Token DefKindTok = getCurToken();

if (expectIdentifierOrKeyword(P))
if (expectIdentifierOrKeyword(*this))
break;

P.ConsumeToken();
ConsumeToken();

if (getOpenACCDefaultClauseKind(DefKindTok) ==
OpenACCDefaultClauseKind::Invalid)
P.Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);

break;
}
case OpenACCClauseKind::If: {
ExprResult CondExpr = ParseOpenACCConditionalExpr(P);
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
// An invalid expression can be just about anything, so just give up on
// this clause list.
if (CondExpr.isInvalid())
return true;
break;
}
case OpenACCClauseKind::Attach:
case OpenACCClauseKind::Copy:
case OpenACCClauseKind::Delete:
case OpenACCClauseKind::Detach:
case OpenACCClauseKind::Device:
case OpenACCClauseKind::DeviceResident:
case OpenACCClauseKind::DevicePtr:
case OpenACCClauseKind::FirstPrivate:
case OpenACCClauseKind::Host:
case OpenACCClauseKind::Link:
case OpenACCClauseKind::NoCreate:
case OpenACCClauseKind::Present:
case OpenACCClauseKind::Private:
case OpenACCClauseKind::UseDevice:
if (ParseOpenACCClauseVarList(Kind))
return true;
break;
default:
llvm_unreachable("Not a required parens type?");
}
Expand All @@ -391,7 +542,7 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
if (!Parens.consumeOpen()) {
switch (Kind) {
case OpenACCClauseKind::Self: {
ExprResult CondExpr = ParseOpenACCConditionalExpr(P);
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
// An invalid expression can be just about anything, so just give up on
// this clause list.
if (CondExpr.isInvalid())
Expand All @@ -407,62 +558,6 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
return false;
}

// The OpenACC Clause List is a comma or space-delimited list of clauses (see
// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
// really have its owner grammar and each individual one has its own definition.
// However, they all are named with a single-identifier (or auto/default!)
// token, followed in some cases by either braces or parens.
bool ParseOpenACCClause(Parser &P) {
// A number of clause names are actually keywords, so accept a keyword that
// can be converted to a name.
if (expectIdentifierOrKeyword(P))
return true;

OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken());

if (Kind == OpenACCClauseKind::Invalid)
return P.Diag(P.getCurToken(), diag::err_acc_invalid_clause)
<< P.getCurToken().getIdentifierInfo();

// Consume the clause name.
P.ConsumeToken();

return ParseOpenACCClauseParams(P, Kind);
}

// Skip until we see the end of pragma token, but don't consume it. This is us
// just giving up on the rest of the pragma so we can continue executing. We
// have to do this because 'SkipUntil' considers paren balancing, which isn't
// what we want.
void SkipUntilEndOfDirective(Parser &P) {
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
P.ConsumeAnyToken();
}

// OpenACC 3.3, section 1.7:
// To simplify the specification and convey appropriate constraint information,
// a pqr-list is a comma-separated list of pdr items. The one exception is a
// clause-list, which is a list of one or more clauses optionally separated by
// commas.
void ParseOpenACCClauseList(Parser &P) {
bool FirstClause = true;
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) {
// Comma is optional in a clause-list.
if (!FirstClause && P.getCurToken().is(tok::comma))
P.ConsumeToken();
FirstClause = false;

// Recovering from a bad clause is really difficult, so we just give up on
// error.
if (ParseOpenACCClause(P)) {
SkipUntilEndOfDirective(P);
return;
}
}
}

} // namespace

/// OpenACC 3.3, section 2.16:
/// In this section and throughout the specification, the term wait-argument
/// means:
Expand Down Expand Up @@ -664,7 +759,7 @@ void Parser::ParseOpenACCDirective() {
}

// Parses the list of clauses, if present.
ParseOpenACCClauseList(*this);
ParseOpenACCClauseList();

Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
assert(Tok.is(tok::annot_pragma_openacc_end) &&
Expand Down
46 changes: 34 additions & 12 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7723,9 +7723,19 @@ bool Sema::CheckNonDependentConversions(
++I) {
QualType ParamType = ParamTypes[I + Offset];
if (!ParamType->isDependentType()) {
unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed
? 0
: (ThisConversions + I);
unsigned ConvIdx;
if (PO == OverloadCandidateParamOrder::Reversed) {
ConvIdx = Args.size() - 1 - I;
assert(Args.size() + ThisConversions == 2 &&
"number of args (including 'this') must be exactly 2 for "
"reversed order");
// For members, there would be only one arg 'Args[0]' whose ConvIdx
// would also be 0. 'this' got ConvIdx = 1 previously.
assert(!HasThisConversion || (ConvIdx == 0 && I == 0));
} else {
// For members, 'this' got ConvIdx = 0 previously.
ConvIdx = ThisConversions + I;
}
Conversions[ConvIdx]
= TryCopyInitialization(*this, Args[I], ParamType,
SuppressUserConversions,
Expand Down Expand Up @@ -10121,11 +10131,23 @@ getImplicitObjectParamType(ASTContext &Context, const FunctionDecl *F) {
return M->getFunctionObjectParameterReferenceType();
}

static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1,
const FunctionDecl *F2) {
// As a Clang extension, allow ambiguity among F1 and F2 if they represent
// represent the same entity.
static bool allowAmbiguity(ASTContext &Context, const FunctionDecl *F1,
const FunctionDecl *F2) {
if (declaresSameEntity(F1, F2))
return true;

auto PT1 = F1->getPrimaryTemplate();
auto PT2 = F2->getPrimaryTemplate();
if (PT1 && PT2) {
if (declaresSameEntity(PT1, PT2) ||
declaresSameEntity(PT1->getInstantiatedFromMemberTemplate(),
PT2->getInstantiatedFromMemberTemplate()))
return true;
}
// TODO: It is not clear whether comparing parameters is necessary (i.e.
// different functions with same params). Consider removing this (as no test
// fail w/o it).
auto NextParam = [&](const FunctionDecl *F, unsigned &I, bool First) {
if (First) {
if (std::optional<QualType> T = getImplicitObjectParamType(Context, F))
Expand Down Expand Up @@ -10329,14 +10351,14 @@ bool clang::isBetterOverloadCandidate(
case ImplicitConversionSequence::Worse:
if (Cand1.Function && Cand2.Function &&
Cand1.isReversed() != Cand2.isReversed() &&
haveSameParameterTypes(S.Context, Cand1.Function, Cand2.Function)) {
allowAmbiguity(S.Context, Cand1.Function, Cand2.Function)) {
// Work around large-scale breakage caused by considering reversed
// forms of operator== in C++20:
//
// When comparing a function against a reversed function with the same
// parameter types, if we have a better conversion for one argument and
// a worse conversion for the other, the implicit conversion sequences
// are treated as being equally good.
// When comparing a function against a reversed function, if we have a
// better conversion for one argument and a worse conversion for the
// other, the implicit conversion sequences are treated as being equally
// good.
//
// This prevents a comparison function from being considered ambiguous
// with a reversed form that is written in the same way.
Expand Down Expand Up @@ -14526,7 +14548,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
llvm::SmallVector<FunctionDecl*, 4> AmbiguousWith;
for (OverloadCandidate &Cand : CandidateSet) {
if (Cand.Viable && Cand.Function && Cand.isReversed() &&
haveSameParameterTypes(Context, Cand.Function, FnDecl)) {
allowAmbiguity(Context, Cand.Function, FnDecl)) {
for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
if (CompareImplicitConversionSequences(
*this, OpLoc, Cand.Conversions[ArgIdx],
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ Response HandleFunction(const FunctionDecl *Function,
(!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
return Response::ChangeDecl(Function->getLexicalDeclContext());
}

if (ForConstraintInstantiation && Function->getFriendObjectKind())
return Response::ChangeDecl(Function->getLexicalDeclContext());
return Response::UseNextDecl(Function);
}

Expand Down
61 changes: 41 additions & 20 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3037,12 +3037,17 @@ ASTReader::ReadControlBlock(ModuleFile &F,
// location info are setup, in ReadAST.
SourceLocation ImportLoc =
ReadUntranslatedSourceLocation(Record[Idx++]);
off_t StoredSize = (off_t)Record[Idx++];
time_t StoredModTime = (time_t)Record[Idx++];
auto FirstSignatureByte = Record.begin() + Idx;
ASTFileSignature StoredSignature = ASTFileSignature::create(
FirstSignatureByte, FirstSignatureByte + ASTFileSignature::size);
Idx += ASTFileSignature::size;
off_t StoredSize = !IsImportingStdCXXModule ? (off_t)Record[Idx++] : 0;
time_t StoredModTime =
!IsImportingStdCXXModule ? (time_t)Record[Idx++] : 0;

ASTFileSignature StoredSignature;
if (!IsImportingStdCXXModule) {
auto FirstSignatureByte = Record.begin() + Idx;
StoredSignature = ASTFileSignature::create(
FirstSignatureByte, FirstSignatureByte + ASTFileSignature::size);
Idx += ASTFileSignature::size;
}

std::string ImportedName = ReadString(Record, Idx);
std::string ImportedFile;
Expand All @@ -3057,18 +3062,19 @@ ASTReader::ReadControlBlock(ModuleFile &F,
ImportedFile = PP.getHeaderSearchInfo().getPrebuiltModuleFileName(
ImportedName, /*FileMapOnly*/ !IsImportingStdCXXModule);

if (ImportedFile.empty()) {
// It is deprecated for C++20 Named modules to use the implicitly
// paths.
if (IsImportingStdCXXModule)
Diag(clang::diag::warn_reading_std_cxx_module_by_implicit_paths)
<< ImportedName;

// Use BaseDirectoryAsWritten to ensure we use the same path in the
// ModuleCache as when writing.
ImportedFile = ReadPath(BaseDirectoryAsWritten, Record, Idx);
} else
SkipPath(Record, Idx);
// For C++20 Modules, we won't record the path to the imported modules
// in the BMI
if (!IsImportingStdCXXModule) {
if (ImportedFile.empty()) {
// Use BaseDirectoryAsWritten to ensure we use the same path in the
// ModuleCache as when writing.
ImportedFile = ReadPath(BaseDirectoryAsWritten, Record, Idx);
} else
SkipPath(Record, Idx);
} else if (ImportedFile.empty()) {
Diag(clang::diag::err_failed_to_find_module_file) << ImportedName;
return Missing;
}

// If our client can't cope with us being out of date, we can't cope with
// our dependency being missing.
Expand Down Expand Up @@ -5584,8 +5590,23 @@ bool ASTReader::readASTFileControlBlock(
while (Idx < N) {
// Read information about the AST file.

// Kind, StandardCXXModule, ImportLoc, Size, ModTime, Signature
Idx += 1 + 1 + 1 + 1 + 1 + ASTFileSignature::size;
// Skip Kind
Idx++;
bool IsStandardCXXModule = Record[Idx++];

// Skip ImportLoc
Idx++;

// In C++20 Modules, we don't record the path to imported
// modules in the BMI files.
if (IsStandardCXXModule) {
std::string ModuleName = ReadString(Record, Idx);
Listener.visitImport(ModuleName, /*Filename=*/"");
continue;
}

// Skip Size, ModTime and Signature
Idx += 1 + 1 + ASTFileSignature::size;
std::string ModuleName = ReadString(Record, Idx);
std::string Filename = ReadString(Record, Idx);
ResolveImportedPath(Filename, ModuleDir);
Expand Down
19 changes: 12 additions & 7 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1411,15 +1411,20 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Record.push_back(M.StandardCXXModule);
AddSourceLocation(M.ImportLoc, Record);

// If we have calculated signature, there is no need to store
// the size or timestamp.
Record.push_back(M.Signature ? 0 : M.File.getSize());
Record.push_back(M.Signature ? 0 : getTimestampForOutput(M.File));

llvm::append_range(Record, M.Signature);
// We don't want to hard code the information about imported modules
// in the C++20 named modules.
if (!M.StandardCXXModule) {
// If we have calculated signature, there is no need to store
// the size or timestamp.
Record.push_back(M.Signature ? 0 : M.File.getSize());
Record.push_back(M.Signature ? 0 : getTimestampForOutput(M.File));
llvm::append_range(Record, M.Signature);
}

AddString(M.ModuleName, Record);
AddPath(M.FileName, Record);

if (!M.StandardCXXModule)
AddPath(M.FileName, Record);
}
Stream.EmitRecord(IMPORTS, Record);
}
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ void NonLocalizedStringChecker::setNonLocalizedState(const SVal S,


static bool isDebuggingName(std::string name) {
return StringRef(name).lower().find("debug") != StringRef::npos;
return StringRef(name).contains_insensitive("debug");
}

/// Returns true when, heuristically, the analyzer may be analyzing debugging
Expand Down Expand Up @@ -1248,8 +1248,8 @@ bool PluralMisuseChecker::MethodCrawler::isCheckingPlurality(
BO = B;
}
}
if (VD->getName().lower().find("plural") != StringRef::npos ||
VD->getName().lower().find("singular") != StringRef::npos) {
if (VD->getName().contains_insensitive("plural") ||
VD->getName().contains_insensitive("singular")) {
return true;
}
}
Expand Down
49 changes: 49 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
{{{"fputs"}, 2},
{std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, false),
std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, false), 1}},
{{{"fprintf"}},
{std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, false),
std::bind(&StreamChecker::evalFprintf, _1, _2, _3, _4), 0}},
{{{"ungetc"}, 2},
{std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, false),
std::bind(&StreamChecker::evalUngetc, _1, _2, _3, _4), 1}},
Expand Down Expand Up @@ -339,6 +342,9 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
void evalFputx(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C, bool IsSingleChar) const;

void evalFprintf(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;

void evalUngetc(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;

Expand Down Expand Up @@ -926,6 +932,49 @@ void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call,
C.addTransition(StateFailed);
}

void StreamChecker::evalFprintf(const FnDescription *Desc,
const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
if (Call.getNumArgs() < 2)
return;
SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
if (!StreamSym)
return;

const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
if (!CE)
return;

const StreamState *OldSS = State->get<StreamMap>(StreamSym);
if (!OldSS)
return;

assertStreamStateOpened(OldSS);

NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
SValBuilder &SVB = C.getSValBuilder();
auto &ACtx = C.getASTContext();
auto Cond = SVB.evalBinOp(State, BO_GE, RetVal, SVB.makeZeroVal(ACtx.IntTy),
SVB.getConditionType())
.getAs<DefinedOrUnknownSVal>();
if (!Cond)
return;
ProgramStateRef StateNotFailed, StateFailed;
std::tie(StateNotFailed, StateFailed) = State->assume(*Cond);

StateNotFailed =
StateNotFailed->set<StreamMap>(StreamSym, StreamState::getOpened(Desc));
C.addTransition(StateNotFailed);

// Add transition for the failed state. The resulting value of the file
// position indicator for the stream is indeterminate.
StateFailed = StateFailed->set<StreamMap>(
StreamSym, StreamState::getOpened(Desc, ErrorFError, true));
C.addTransition(StateFailed);
}

void StreamChecker::evalUngetc(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
Expand Down
14 changes: 13 additions & 1 deletion clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class HTMLDiagnostics : public PathDiagnosticConsumer {
bool noDir = false;
const Preprocessor &PP;
const bool SupportsCrossFileDiagnostics;
llvm::StringSet<> EmittedHashes;

public:
HTMLDiagnostics(PathDiagnosticConsumerOptions DiagOpts,
Expand Down Expand Up @@ -301,6 +302,17 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
}
}

SmallString<32> IssueHash = getIssueHash(D, PP);
auto [It, IsNew] = EmittedHashes.insert(IssueHash);
if (!IsNew) {
// We've already emitted a duplicate issue. It'll get overwritten anyway.
return;
}

// FIXME: This causes each file to be re-parsed and syntax-highlighted
// and macro-expanded separately for each report. We could cache such rewrites
// across all reports and only re-do the part that's actually different:
// the warning/note bubbles.
std::string report = GenerateHTML(D, R, SMgr, path, declName.c_str());
if (report.empty()) {
llvm::errs() << "warning: no diagnostics generated for main file.\n";
Expand Down Expand Up @@ -332,7 +344,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
<< declName.c_str() << "-" << offsetDecl << "-";
}

FileName << StringRef(getIssueHash(D, PP)).substr(0, 6).str() << ".html";
FileName << StringRef(IssueHash).substr(0, 6).str() << ".html";

SmallString<128> ResultPath;
llvm::sys::path::append(ResultPath, Directory, FileName.str());
Expand Down
17 changes: 17 additions & 0 deletions clang/test/Analysis/stream-error.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,23 @@ void error_fputs(void) {
fputs("ABC", F); // expected-warning {{Stream might be already closed}}
}

void error_fprintf(void) {
FILE *F = tmpfile();
if (!F)
return;
int Ret = fprintf(F, "aaa");
if (Ret >= 0) {
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
fprintf(F, "bbb"); // no-warning
} else {
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
fprintf(F, "bbb"); // expected-warning {{might be 'indeterminate'}}
}
fclose(F);
fprintf(F, "ccc"); // expected-warning {{Stream might be already closed}}
}

void error_ungetc() {
FILE *F = tmpfile();
if (!F)
Expand Down
11 changes: 8 additions & 3 deletions clang/test/Analysis/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ void check_fputs(void) {
fclose(fp);
}

void check_fprintf(void) {
FILE *fp = tmpfile();
fprintf(fp, "ABC"); // expected-warning {{Stream pointer might be NULL}}
fclose(fp);
}

void check_ungetc(void) {
FILE *fp = tmpfile();
ungetc('A', fp); // expected-warning {{Stream pointer might be NULL}}
Expand Down Expand Up @@ -271,9 +277,8 @@ void check_escape4(void) {
return;
fwrite("1", 1, 1, F); // may fail

// no escape at (non-StreamChecker-handled) system call
// FIXME: all such calls should be handled by the checker
fprintf(F, "0");
// no escape at a non-StreamChecker-handled system call
setbuf(F, "0");

fwrite("1", 1, 1, F); // expected-warning {{might be 'indeterminate'}}
fclose(F);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,124 @@ bool x = X() == X(); // expected-warning {{ambiguous}}
}
} // namespace P2468R2

namespace GH53954{
namespace friend_template_1 {
struct P {
template <class T>
friend bool operator==(const P&, const T&) { return true; } // expected-note {{candidate}} \
// expected-note {{ambiguous candidate function with reversed arguments}}
};
struct A : public P {};
struct B : public P {};
bool check(A a, B b) { return a == b; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}
}

namespace friend_template_2 {
struct P {
template <class T>
friend bool operator==(const T&, const P&) { return true; } // expected-note {{candidate}} \
// expected-note {{ambiguous candidate function with reversed arguments}}
};
struct A : public P {};
struct B : public P {};
bool check(A a, B b) { return a == b; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}
}

namespace friend_template_class_template {
template<class S>
struct P {
template <class T>
friend bool operator==(const T&, const P&) { // expected-note 2 {{candidate}}
return true;
}
};
struct A : public P<int> {};
struct B : public P<bool> {};
bool check(A a, B b) { return a == b; } // expected-warning {{ambiguous}}
}

namespace friend_template_fixme {
// FIXME(GH70210): This should not rewrite operator== and definitely not a hard error.
struct P {
template <class T>
friend bool operator==(const T &, const P &) { return true; } // expected-note 2 {{candidate}}
template <class T>
friend bool operator!=(const T &, const P &) { return true; } // expected-note {{candidate}}
};
struct A : public P {};
struct B : public P {};
bool check(A a, B b) { return a != b; } // expected-error{{ambiguous}}
}

namespace member_template_1 {
struct P {
template<class S>
bool operator==(const S &) const; // expected-note {{candidate}} \
// expected-note {{ambiguous candidate function with reversed arguments}}
};
struct A : public P {};
struct B : public P {};
bool check(A a, B b) { return a == b; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}
} // namespace member_template

namespace member_template_2{
template <typename T>
class Foo {
public:
template <typename U = T>
bool operator==(const Foo& other) const;
};
bool x = Foo<int>{} == Foo<int>{};
} // namespace template_member_opeqeq

namespace non_member_template_1 {
struct P {};
template<class S>
bool operator==(const P&, const S &); // expected-note {{candidate}} \
// expected-note {{ambiguous candidate function with reversed arguments}}

struct A : public P {};
struct B : public P {};
bool check(A a, B b) { return a == b; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}

template<class S> bool operator!=(const P&, const S &);
bool fine(A a, B b) { return a == b; } // Ok. Found a matching operator!=.
} // namespace non_member_template_1

namespace non_member_template_2 {
struct P {};
template<class S>
bool operator==(const S&, const P&); // expected-note {{candidate}} \
// expected-note {{ambiguous candidate function with reversed arguments}}

struct A : public P {};
struct B : public P {};
bool check(A a, B b) { return a == b; } // expected-warning {{use of overloaded operator '==' (with operand types 'A' and 'B') to be ambiguous}}
} // namespace non_member_template_2

namespace class_and_member_template {
template <class T>
struct S {
template <typename OtherT>
bool operator==(const OtherT &rhs); // expected-note {{candidate}} \
// expected-note {{reversed arguments}}
};
struct A : S<int> {};
struct B : S<bool> {};
bool x = A{} == B{}; // expected-warning {{ambiguous}}
} // namespace class_and_member_template

namespace ambiguous_case {
template <class T>
struct Foo {};
template <class T, class U> bool operator==(Foo<U>, Foo<T*>); // expected-note{{candidate}}
template <class T, class U> bool operator==(Foo<T*>, Foo<U>); // expected-note{{candidate}}

void test() {
Foo<int*>() == Foo<int*>(); // expected-error{{ambiguous}}
}
} // namespace ambiguous_case
} // namespace
namespace ADL_GH68901{
namespace test1 {
namespace A {
Expand Down
File renamed without changes.
28 changes: 16 additions & 12 deletions clang/test/CodeGen/aarch64-branch-protection-attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,29 +63,33 @@ __attribute__ ((target("branch-protection=pac-ret+pc+bti")))
void pauthlr_bti() {}
// CHECK: define{{.*}} void @pauthlr_bti() #[[#PAUTHLR_BTI:]]

__attribute__ ((target("branch-protection=gcs")))
void gcs() {}
// CHECK: define{{.*}} void @gcs() #[[#GCS:]]

// CHECK-DAG: attributes #[[#NONE]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#NONE]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}} "sign-return-address"="none"

// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement"="true" "guarded-control-stack"="true" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true" "guarded-control-stack"="false" {{.*}} "sign-return-address"="none"

// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "branch-target-enforcement"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}}"branch-target-enforcement"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key"

// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "branch-target-enforcement"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="b_key"
// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="b_key"

// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement"="true" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement"="true" "guarded-control-stack"="false" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key"


// CHECK-DAG: attributes #[[#PAUTHLR]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAUTHLR]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PAUTHLR_BKEY]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
// CHECK-DAG: attributes #[[#PAUTHLR_BKEY]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="b_key"

// CHECK-DAG: attributes #[[#PAUTHLR_LEAF]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAUTHLR_LEAF]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#PAUTHLR_BTI]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="true" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
// CHECK-DAG: attributes #[[#PAUTHLR_BTI]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="true" "guarded-control-stack"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"

// CHECK-DAG: attributes #[[#GCS]] = { {{.*}}"branch-target-enforcement"="false" "guarded-control-stack"="true" {{.*}} "sign-return-address"="none"
Loading