4 changes: 0 additions & 4 deletions bolt/include/bolt/Passes/FrameAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,6 @@ class FrameAnalysis {
std::unique_ptr<StackPointerTracking>>
SPTMap;

/// A vector that stores ids of the allocators that are used in SPT
/// computation
std::vector<MCPlusBuilder::AllocatorIdTy> SPTAllocatorsId;

public:
explicit FrameAnalysis(BinaryContext &BC, BinaryFunctionCallGraph &CG);

Expand Down
2 changes: 1 addition & 1 deletion bolt/include/bolt/Passes/IndirectCallPromotion.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class IndirectCallPromotion : public BinaryFunctionPass {
struct Location {
MCSymbol *Sym{nullptr};
uint64_t Addr{0};
bool isValid() const { return Sym || (!Sym && Addr != 0); }
bool isValid() const { return Sym || Addr != 0; }
Location() {}
explicit Location(MCSymbol *Sym) : Sym(Sym) {}
explicit Location(uint64_t Addr) : Addr(Addr) {}
Expand Down
7 changes: 0 additions & 7 deletions bolt/include/bolt/Rewrite/DWARFRewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,6 @@ class DWARFRewriter {
DIEValue &HighPCAttrInfo,
std::optional<uint64_t> RangesBase = std::nullopt);

/// Adds a \p Str to .debug_str section.
/// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using
/// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets
/// for this contribution of \p Unit.
void addStringHelper(DIEBuilder &DIEBldr, DIE &Die, const DWARFUnit &Unit,
DIEValue &DIEAttrInfo, StringRef Str);

public:
DWARFRewriter(BinaryContext &BC) : BC(BC) {}

Expand Down
15 changes: 15 additions & 0 deletions bolt/lib/Core/BinaryFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,21 @@ void BinaryFunction::handleAArch64IndirectCall(MCInst &Instruction,
}
}

std::optional<MCInst>
BinaryFunction::disassembleInstructionAtOffset(uint64_t Offset) const {
assert(CurrentState == State::Empty && "Function should not be disassembled");
assert(Offset < MaxSize && "Invalid offset");
ErrorOr<ArrayRef<unsigned char>> FunctionData = getData();
assert(FunctionData && "Cannot get function as data");
MCInst Instr;
uint64_t InstrSize = 0;
const uint64_t InstrAddress = getAddress() + Offset;
if (BC.DisAsm->getInstruction(Instr, InstrSize, FunctionData->slice(Offset),
InstrAddress, nulls()))
return Instr;
return std::nullopt;
}

Error BinaryFunction::disassemble() {
NamedRegionTimer T("disassemble", "Disassemble function", "buildfuncs",
"Build Binary Functions", opts::TimeBuild);
Expand Down
29 changes: 15 additions & 14 deletions bolt/lib/Core/ParallelUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,20 @@ void runOnEachFunctionWithUniqueAllocId(
LLVM_DEBUG(T.stopTimer());
};

unsigned AllocId = 1;
auto EnsureAllocatorExists = [&BC](unsigned AllocId) {
if (!BC.MIB->checkAllocatorExists(AllocId)) {
MCPlusBuilder::AllocatorIdTy Id =
BC.MIB->initializeNewAnnotationAllocator();
(void)Id;
assert(AllocId == Id && "unexpected allocator id created");
}
};

if (opts::NoThreads || ForceSequential) {
runBlock(BC.getBinaryFunctions().begin(), BC.getBinaryFunctions().end(), 0);
EnsureAllocatorExists(AllocId);
runBlock(BC.getBinaryFunctions().begin(), BC.getBinaryFunctions().end(),
AllocId);
return;
}
// This lock is used to postpone task execution
Expand All @@ -205,32 +217,21 @@ void runOnEachFunctionWithUniqueAllocId(
ThreadPoolInterface &Pool = getThreadPool();
auto BlockBegin = BC.getBinaryFunctions().begin();
unsigned CurrentCost = 0;
unsigned AllocId = 1;
for (auto It = BC.getBinaryFunctions().begin();
It != BC.getBinaryFunctions().end(); ++It) {
BinaryFunction &BF = It->second;
CurrentCost += computeCostFor(BF, SkipPredicate, SchedPolicy);

if (CurrentCost >= BlockCost) {
if (!BC.MIB->checkAllocatorExists(AllocId)) {
MCPlusBuilder::AllocatorIdTy Id =
BC.MIB->initializeNewAnnotationAllocator();
(void)Id;
assert(AllocId == Id && "unexpected allocator id created");
}
EnsureAllocatorExists(AllocId);
Pool.async(runBlock, BlockBegin, std::next(It), AllocId);
AllocId++;
BlockBegin = std::next(It);
CurrentCost = 0;
}
}

if (!BC.MIB->checkAllocatorExists(AllocId)) {
MCPlusBuilder::AllocatorIdTy Id =
BC.MIB->initializeNewAnnotationAllocator();
(void)Id;
assert(AllocId == Id && "unexpected allocator id created");
}
EnsureAllocatorExists(AllocId);

Pool.async(runBlock, BlockBegin, BC.getBinaryFunctions().end(), AllocId);
Lock.unlock();
Expand Down
5 changes: 0 additions & 5 deletions bolt/lib/Passes/FrameAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,11 +561,6 @@ FrameAnalysis::FrameAnalysis(BinaryContext &BC, BinaryFunctionCallGraph &CG)
NamedRegionTimer T1("clearspt", "clear spt", "FA", "FA breakdown",
opts::TimeFA);
clearSPTMap();

// Clean up memory allocated for annotation values
if (!opts::NoThreads)
for (MCPlusBuilder::AllocatorIdTy Id : SPTAllocatorsId)
BC.MIB->freeValuesAllocator(Id);
}
}

Expand Down
13 changes: 13 additions & 0 deletions bolt/lib/Profile/DataAggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -773,9 +773,19 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc,

bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
uint64_t Mispreds) {
bool IsReturn = false;
auto handleAddress = [&](uint64_t &Addr, bool IsFrom) -> BinaryFunction * {
if (BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr)) {
Addr -= Func->getAddress();
if (IsFrom) {
auto checkReturn = [&](auto MaybeInst) {
IsReturn = MaybeInst && BC->MIB->isReturn(*MaybeInst);
};
if (Func->hasInstructions())
checkReturn(Func->getInstructionAtOffset(Addr));
else
checkReturn(Func->disassembleInstructionAtOffset(Addr));
}

if (BAT)
Addr = BAT->translate(Func->getAddress(), Addr, IsFrom);
Expand All @@ -792,6 +802,9 @@ bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
};

BinaryFunction *FromFunc = handleAddress(From, /*IsFrom=*/true);
// Ignore returns.
if (IsReturn)
return true;
BinaryFunction *ToFunc = handleAddress(To, /*IsFrom=*/false);
if (!FromFunc && !ToFunc)
return false;
Expand Down
80 changes: 45 additions & 35 deletions bolt/lib/Rewrite/DWARFRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,19 +582,51 @@ static void emitDWOBuilder(const std::string &DWOName,
Rewriter.writeDWOFiles(CU, OverriddenSections, DWOName, LocWriter);
}

void DWARFRewriter::addStringHelper(DIEBuilder &DIEBldr, DIE &Die,
const DWARFUnit &Unit,
DIEValue &DIEAttrInfo, StringRef Str) {
uint32_t NewOffset = StrWriter->addString(Str);
/// Adds a \p Str to .debug_str section.
/// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using
/// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets
/// for this contribution of \p Unit.
static void addStringHelper(DebugStrOffsetsWriter &StrOffstsWriter,
DebugStrWriter &StrWriter, DIEBuilder &DIEBldr,
DIE &Die, const DWARFUnit &Unit,
DIEValue &DIEAttrInfo, StringRef Str) {
uint32_t NewOffset = StrWriter.addString(Str);
if (Unit.getVersion() >= 5) {
StrOffstsWriter->updateAddressMap(DIEAttrInfo.getDIEInteger().getValue(),
NewOffset);
StrOffstsWriter.updateAddressMap(DIEAttrInfo.getDIEInteger().getValue(),
NewOffset);
return;
}
DIEBldr.replaceValue(&Die, DIEAttrInfo.getAttribute(), DIEAttrInfo.getForm(),
DIEInteger(NewOffset));
}

static std::string
updateDWONameCompDir(DebugStrOffsetsWriter &StrOffstsWriter,
DebugStrWriter &StrWriter,
std::unordered_map<std::string, uint32_t> &NameToIndexMap,
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &UnitDIE) {
DIEValue DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_dwo_name);
if (!DWONameAttrInfo)
DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_GNU_dwo_name);
assert(DWONameAttrInfo && "DW_AT_dwo_name is not in Skeleton CU.");
std::string ObjectName;

ObjectName = getDWOName(Unit, NameToIndexMap);
addStringHelper(StrOffstsWriter, StrWriter, DIEBldr, UnitDIE, Unit,
DWONameAttrInfo, ObjectName.c_str());

DIEValue CompDirAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_comp_dir);
assert(CompDirAttrInfo && "DW_AT_comp_dir is not in Skeleton CU.");

if (!opts::DwarfOutputPath.empty()) {
if (!sys::fs::exists(opts::DwarfOutputPath))
sys::fs::create_directory(opts::DwarfOutputPath);
addStringHelper(StrOffstsWriter, StrWriter, DIEBldr, UnitDIE, Unit,
CompDirAttrInfo, opts::DwarfOutputPath.c_str());
}
return ObjectName;
}

using DWARFUnitVec = std::vector<DWARFUnit *>;
using CUPartitionVector = std::vector<DWARFUnitVec>;
/// Partitions CUs in to buckets. Bucket size is controlled by
Expand Down Expand Up @@ -692,33 +724,6 @@ void DWARFRewriter::updateDebugInfo() {
// specified.
std::unordered_map<std::string, uint32_t> NameToIndexMap;

auto updateDWONameCompDir = [&](DWARFUnit &Unit, DIEBuilder &DIEBldr,
DIE &UnitDIE) -> std::string {
DIEValue DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_dwo_name);
if (!DWONameAttrInfo)
DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_GNU_dwo_name);
assert(DWONameAttrInfo && "DW_AT_dwo_name is not in Skeleton CU.");
std::string ObjectName;

{
std::lock_guard<std::mutex> Lock(AccessMutex);
ObjectName = getDWOName(Unit, NameToIndexMap);
}
addStringHelper(DIEBldr, UnitDIE, Unit, DWONameAttrInfo,
ObjectName.c_str());

DIEValue CompDirAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_comp_dir);
assert(CompDirAttrInfo && "DW_AT_comp_dir is not in Skeleton CU.");

if (!opts::DwarfOutputPath.empty()) {
if (!sys::fs::exists(opts::DwarfOutputPath))
sys::fs::create_directory(opts::DwarfOutputPath);
addStringHelper(DIEBldr, UnitDIE, Unit, CompDirAttrInfo,
opts::DwarfOutputPath.c_str());
}
return ObjectName;
};

DWARF5AcceleratorTable DebugNamesTable(opts::CreateDebugNames, BC,
*StrWriter);
DWPState State;
Expand All @@ -741,8 +746,13 @@ void DWARFRewriter::updateDebugInfo() {
DIEBuilder DWODIEBuilder(BC, &(*SplitCU)->getContext(), DebugNamesTable,
Unit);
DWODIEBuilder.buildDWOUnit(**SplitCU);
std::string DWOName = updateDWONameCompDir(
*Unit, *DIEBlder, *DIEBlder->getUnitDIEbyUnit(*Unit));
std::string DWOName = "";
{
std::lock_guard<std::mutex> Lock(AccessMutex);
DWOName = updateDWONameCompDir(*StrOffstsWriter, *StrWriter,
NameToIndexMap, *Unit, *DIEBlder,
*DIEBlder->getUnitDIEbyUnit(*Unit));
}

DebugLoclistWriter DebugLocDWoWriter(*Unit, Unit->getVersion(), true);
DebugRangesSectionWriter *TempRangesSectionWriter = RangesSectionWriter;
Expand Down
35 changes: 35 additions & 0 deletions bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.globl main
.type main, %function
main:
.cfi_startproc
cmpq $0x3, %rdi
jae .L4
cmpq $0x1, %rdi
jne .L4
mov .Ljt_pic+8(%rip), %rax
lea .Ljt_pic(%rip), %rdx
add %rdx, %rax
jmpq *%rax
.L1:
movq $0x1, %rax
jmp .L5
.L2:
movq $0x0, %rax
jmp .L5
.L3:
movq $0x2, %rax
jmp .L5
.L4:
mov $0x3, %rax
.L5:
retq
.cfi_endproc

.section .rodata
.align 16
.Ljt_pic:
.long .L1 - .Ljt_pic
.long .L2 - .Ljt_pic
.long .L3 - .Ljt_pic
.long .L4 - .Ljt_pic

5 changes: 3 additions & 2 deletions bolt/test/X86/bolt-address-translation-yaml.test
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o /dev/null
RUN: FileCheck --input-file %t.yaml-fdata --check-prefix YAML-BAT-CHECK %s

# Test resulting YAML profile with the original binary (no-stale mode)
RUN: llvm-bolt %t.exe -data %t.yaml -o %t.null -dyno-stats \
RUN: llvm-bolt %t.exe -data %t.yaml -o %t.null -dyno-stats 2>&1 \
RUN: | FileCheck --check-prefix CHECK-BOLT-YAML %s

WRITE-BAT-CHECK: BOLT-INFO: Wrote 5 BAT maps
Expand Down Expand Up @@ -63,7 +63,8 @@ YAML-BAT-CHECK-NEXT: blocks:
YAML-BAT-CHECK: - bid: 1
YAML-BAT-CHECK-NEXT: insns: [[#]]
YAML-BAT-CHECK-NEXT: hash: 0xD70DC695320E0010
YAML-BAT-CHECK-NEXT: succ: {{.*}} { bid: 2, cnt: [[#]] }
YAML-BAT-CHECK-NEXT: succ: {{.*}} { bid: 2, cnt: [[#]]

CHECK-BOLT-YAML: pre-processing profile using YAML profile reader
CHECK-BOLT-YAML-NEXT: 5 out of 16 functions in the binary (31.2%) have non-empty execution profile
CHECK-BOLT-YAML-NOT: invalid (possibly stale) profile
9 changes: 9 additions & 0 deletions bolt/test/X86/jump-table-fixed-ref-pic.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Verify that BOLT detects fixed destination of indirect jump for PIC
# case.

XFAIL: *

RUN: %clang %cflags -no-pie %S/Inputs/jump-table-fixed-ref-pic.s -Wl,-q -o %t
RUN: llvm-bolt %t --relocs -o %t.null 2>&1 | FileCheck %s

CHECK: BOLT-INFO: fixed indirect branch detected in main
40 changes: 40 additions & 0 deletions bolt/test/runtime/bolt-reserved.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// REQUIRES: system-linux

/*
* Check that llvm-bolt uses reserved space in a binary for allocating
* new sections.
*/

// RUN: %clang %s -o %t.exe -Wl,-q
// RUN: llvm-bolt %t.exe -o %t.bolt.exe 2>&1 | FileCheck %s
// RUN: %t.bolt.exe

// CHECK: BOLT-INFO: using reserved space

/*
* Check that llvm-bolt detects a condition when the reserved space is
* not enough for allocating new sections.
*/

// RUN: %clang %s -o %t.exe -Wl,--no-eh-frame-hdr -Wl,-q -DTINY
// RUN: not llvm-bolt %t.exe -o %t.bolt.exe 2>&1 | \
// RUN: FileCheck %s --check-prefix=CHECK-TINY

// CHECK-TINY: BOLT-ERROR: reserved space (1 byte) is smaller than required

#ifdef TINY
#define RSIZE "1"
#else
#define RSIZE "8192 * 1024"
#endif

asm(".pushsection .text \n\
.globl __bolt_reserved_start \n\
.type __bolt_reserved_start, @object \n\
__bolt_reserved_start: \n\
.space " RSIZE " \n\
.globl __bolt_reserved_end \n\
__bolt_reserved_end: \n\
.popsection");

int main() { return 0; }
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap() {
static const HeaderMapCollector::RegexHeaderMap STLPostfixHeaderMap = {
{"include/__stdarg___gnuc_va_list.h$", "<cstdarg>"},
{"include/__stdarg___va_copy.h$", "<cstdarg>"},
{"include/__stdarg_header_macro.h$", "<cstdarg>"},
{"include/__stdarg_va_arg.h$", "<cstdarg>"},
{"include/__stdarg_va_copy.h$", "<cstdarg>"},
{"include/__stdarg_va_list.h$", "<cstdarg>"},
{"include/__stddef_header_macro.h$", "<cstddef>"},
{"include/__stddef_max_align_t.h$", "<cstddef>"},
{"include/__stddef_null.h$", "<cstddef>"},
{"include/__stddef_nullptr_t.h$", "<cstddef>"},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,11 @@ std::optional<RenamerClangTidyCheck::FailureInfo>
ReservedIdentifierCheck::getDeclFailureInfo(const NamedDecl *Decl,
const SourceManager &) const {
assert(Decl && Decl->getIdentifier() && !Decl->getName().empty() &&
!Decl->isImplicit() &&
"Decl must be an explicit identifier with a name.");
// Implicit identifiers cannot fail.
if (Decl->isImplicit())
return std::nullopt;

return getFailureInfoImpl(
Decl->getName(), isa<TranslationUnitDecl>(Decl->getDeclContext()),
/*IsMacro = */ false, getLangOpts(), Invert, AllowedIdentifiers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,25 @@ namespace clang::tidy::bugprone {

void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
returnStmt(hasReturnValue(declRefExpr(to(parmVarDecl(hasType(
hasCanonicalType(matchers::isReferenceToConst())))))))
returnStmt(
hasReturnValue(declRefExpr(to(parmVarDecl(hasType(hasCanonicalType(
qualType(matchers::isReferenceToConst()).bind("type"))))))),
hasAncestor(functionDecl(hasReturnTypeLoc(
loc(qualType(hasCanonicalType(equalsBoundNode("type"))))))))
.bind("ret"),
this);
}

void ReturnConstRefFromParameterCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *R = Result.Nodes.getNodeAs<ReturnStmt>("ret");
diag(R->getRetValue()->getBeginLoc(),
"returning a constant reference parameter may cause a use-after-free "
"when the parameter is constructed from a temporary");
const SourceRange Range = R->getRetValue()->getSourceRange();
if (Range.isInvalid())
return;
diag(Range.getBegin(),
"returning a constant reference parameter may cause use-after-free "
"when the parameter is constructed from a temporary")
<< Range;
}

} // namespace clang::tidy::bugprone
5 changes: 3 additions & 2 deletions clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "SignedBitwiseCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"

using namespace clang::ast_matchers;
using namespace clang::ast_matchers::internal;
Expand All @@ -29,8 +30,8 @@ void SignedBitwiseCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) {
const auto SignedIntegerOperand =
(IgnorePositiveIntegerLiterals
? expr(ignoringImpCasts(hasType(isSignedInteger())),
unless(integerLiteral()))
? expr(ignoringImpCasts(
allOf(hasType(isSignedInteger()), unless(integerLiteral()))))
: expr(ignoringImpCasts(hasType(isSignedInteger()))))
.bind("signed-operand");

Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ void UseStdPrintCheck::check(const MatchFinder::MatchResult &Result) {
if (!Converter.canApply()) {
diag(PrintfCall->getBeginLoc(),
"unable to use '%0' instead of %1 because %2")
<< ReplacementFunction << OldFunction->getIdentifier()
<< PrintfCall->getSourceRange() << ReplacementFunction
<< OldFunction->getIdentifier()
<< Converter.conversionNotPossibleReason();
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,10 @@ IdentifierNamingCheck::getFailureInfo(
std::optional<RenamerClangTidyCheck::FailureInfo>
IdentifierNamingCheck::getDeclFailureInfo(const NamedDecl *Decl,
const SourceManager &SM) const {
// Implicit identifiers cannot be renamed.
if (Decl->isImplicit())
return std::nullopt;

SourceLocation Loc = Decl->getLocation();
const FileStyle &FileStyle = getStyleForFile(SM.getFilename(Loc));
if (!FileStyle.isActive())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ void StaticAccessedThroughInstanceCheck::check(

const Expr *BaseExpr = MemberExpression->getBase();

// Do not warn for overloaded -> operators.
if (isa<CXXOperatorCallExpr>(BaseExpr))
return;

const QualType BaseType =
BaseExpr->getType()->isPointerType()
? BaseExpr->getType()->getPointeeType().getUnqualifiedType()
Expand All @@ -89,17 +85,30 @@ void StaticAccessedThroughInstanceCheck::check(
return;

SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc();
auto Diag =
diag(MemberExprStartLoc, "static member accessed through instance");

if (BaseExpr->HasSideEffects(*AstContext) ||
getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold)
return;
auto CreateFix = [&] {
return FixItHint::CreateReplacement(
CharSourceRange::getCharRange(MemberExprStartLoc,
MemberExpression->getMemberLoc()),
BaseTypeName + "::");
};

{
auto Diag =
diag(MemberExprStartLoc, "static member accessed through instance");

if (getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold)
return;

if (!BaseExpr->HasSideEffects(*AstContext,
/* IncludePossibleEffects =*/true)) {
Diag << CreateFix();
return;
}
}

Diag << FixItHint::CreateReplacement(
CharSourceRange::getCharRange(MemberExprStartLoc,
MemberExpression->getMemberLoc()),
BaseTypeName + "::");
diag(MemberExprStartLoc, "member base expression may carry some side effects",
DiagnosticIDs::Level::Note)
<< BaseExpr->getSourceRange() << CreateFix();
}

} // namespace clang::tidy::readability
27 changes: 23 additions & 4 deletions clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,43 @@
//===----------------------------------------------------------------------===//

#include "StringCompareCheck.h"
#include "../utils/FixItHintUtils.h"
#include "../utils/OptionsUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/FixIt.h"
#include "llvm/ADT/StringRef.h"

using namespace clang::ast_matchers;
namespace optutils = clang::tidy::utils::options;

namespace clang::tidy::readability {

static const StringRef CompareMessage = "do not use 'compare' to test equality "
"of strings; use the string equality "
"operator instead";

static const StringRef DefaultStringLikeClasses = "::std::basic_string;"
"::std::basic_string_view";

StringCompareCheck::StringCompareCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
StringLikeClasses(optutils::parseStringList(
Options.get("StringLikeClasses", DefaultStringLikeClasses))) {}

void StringCompareCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "StringLikeClasses",
optutils::serializeStringList(StringLikeClasses));
}

void StringCompareCheck::registerMatchers(MatchFinder *Finder) {
if (StringLikeClasses.empty()) {
return;
}
const auto StrCompare = cxxMemberCallExpr(
callee(cxxMethodDecl(hasName("compare"),
ofClass(classTemplateSpecializationDecl(
hasName("::std::basic_string"))))),
callee(cxxMethodDecl(hasName("compare"), ofClass(cxxRecordDecl(hasAnyName(
StringLikeClasses))))),
hasArgument(0, expr().bind("str2")), argumentCountIs(1),
callee(memberExpr().bind("str1")));

Expand Down
10 changes: 8 additions & 2 deletions clang-tools-extra/clang-tidy/readability/StringCompareCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGCOMPARECHECK_H

#include "../ClangTidyCheck.h"
#include <vector>

namespace clang::tidy::readability {

Expand All @@ -20,13 +21,18 @@ namespace clang::tidy::readability {
/// http://clang.llvm.org/extra/clang-tidy/checks/readability/string-compare.html
class StringCompareCheck : public ClangTidyCheck {
public:
StringCompareCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
StringCompareCheck(StringRef Name, ClangTidyContext *Context);

bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus;
}

void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;

private:
const std::vector<StringRef> StringLikeClasses;
};

} // namespace clang::tidy::readability
Expand Down
196 changes: 105 additions & 91 deletions clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct DenseMapInfo<clang::tidy::RenamerClangTidyCheck::NamingCheckId> {
namespace clang::tidy {

namespace {

class NameLookup {
llvm::PointerIntPair<const NamedDecl *, 1, bool> Data;

Expand All @@ -78,6 +79,7 @@ class NameLookup {
operator bool() const { return !hasMultipleResolutions(); }
const NamedDecl *operator*() const { return getDecl(); }
};

} // namespace

static const NamedDecl *findDecl(const RecordDecl &RecDecl,
Expand All @@ -91,6 +93,44 @@ static const NamedDecl *findDecl(const RecordDecl &RecDecl,
return nullptr;
}

/// Returns the function that \p Method is overridding. If There are none or
/// multiple overrides it returns nullptr. If the overridden function itself is
/// overridding then it will recurse up to find the first decl of the function.
static const CXXMethodDecl *getOverrideMethod(const CXXMethodDecl *Method) {
if (Method->size_overridden_methods() != 1)
return nullptr;

while (true) {
Method = *Method->begin_overridden_methods();
assert(Method && "Overridden method shouldn't be null");
unsigned NumOverrides = Method->size_overridden_methods();
if (NumOverrides == 0)
return Method;
if (NumOverrides > 1)
return nullptr;
}
}

static bool hasNoName(const NamedDecl *Decl) {
return !Decl->getIdentifier() || Decl->getName().empty();
}

static const NamedDecl *getFailureForNamedDecl(const NamedDecl *ND) {
const auto *Canonical = cast<NamedDecl>(ND->getCanonicalDecl());
if (Canonical != ND)
return Canonical;

if (const auto *Method = dyn_cast<CXXMethodDecl>(ND)) {
if (const CXXMethodDecl *Overridden = getOverrideMethod(Method))
Canonical = cast<NamedDecl>(Overridden->getCanonicalDecl());

if (Canonical != ND)
return Canonical;
}

return ND;
}

/// Returns a decl matching the \p DeclName in \p Parent or one of its base
/// classes. If \p AggressiveTemplateLookup is `true` then it will check
/// template dependent base classes as well.
Expand Down Expand Up @@ -132,24 +172,6 @@ static NameLookup findDeclInBases(const CXXRecordDecl &Parent,
return NameLookup(Found); // If nullptr, decl wasn't found.
}

/// Returns the function that \p Method is overridding. If There are none or
/// multiple overrides it returns nullptr. If the overridden function itself is
/// overridding then it will recurse up to find the first decl of the function.
static const CXXMethodDecl *getOverrideMethod(const CXXMethodDecl *Method) {
if (Method->size_overridden_methods() != 1)
return nullptr;

while (true) {
Method = *Method->begin_overridden_methods();
assert(Method && "Overridden method shouldn't be null");
unsigned NumOverrides = Method->size_overridden_methods();
if (NumOverrides == 0)
return Method;
if (NumOverrides > 1)
return nullptr;
}
}

namespace {

/// Callback supplies macros to RenamerClangTidyCheck::checkMacro
Expand Down Expand Up @@ -192,10 +214,6 @@ class RenamerClangTidyVisitor
: Check(Check), SM(SM),
AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {}

static bool hasNoName(const NamedDecl *Decl) {
return !Decl->getIdentifier() || Decl->getName().empty();
}

bool shouldVisitTemplateInstantiations() const { return true; }

bool shouldVisitImplicitCode() const { return false; }
Expand Down Expand Up @@ -246,29 +264,10 @@ class RenamerClangTidyVisitor
}

bool VisitNamedDecl(NamedDecl *Decl) {
if (hasNoName(Decl))
return true;

const auto *Canonical = cast<NamedDecl>(Decl->getCanonicalDecl());
if (Canonical != Decl) {
Check->addUsage(Canonical, Decl->getLocation(), SM);
return true;
}

// Fix overridden methods
if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) {
Check->addUsage(Overridden, Method->getLocation(), SM);
return true; // Don't try to add the actual decl as a Failure.
}
}

// Ignore ClassTemplateSpecializationDecl which are creating duplicate
// replacements with CXXRecordDecl.
if (isa<ClassTemplateSpecializationDecl>(Decl))
return true;

Check->checkNamedDecl(Decl, SM);
SourceRange UsageRange =
DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
.getSourceRange();
Check->addUsage(Decl, UsageRange, SM);
return true;
}

Expand Down Expand Up @@ -413,82 +412,97 @@ void RenamerClangTidyCheck::registerPPCallbacks(
std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM, this));
}

void RenamerClangTidyCheck::addUsage(
const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range,
const SourceManager &SourceMgr) {
std::pair<RenamerClangTidyCheck::NamingCheckFailureMap::iterator, bool>
RenamerClangTidyCheck::addUsage(
const RenamerClangTidyCheck::NamingCheckId &FailureId,
SourceRange UsageRange, const SourceManager &SourceMgr) {
// Do nothing if the provided range is invalid.
if (Range.isInvalid())
return;
if (UsageRange.isInvalid())
return {NamingCheckFailures.end(), false};

// If we have a source manager, use it to convert to the spelling location for
// performing the fix. This is necessary because macros can map the same
// spelling location to different source locations, and we only want to fix
// the token once, before it is expanded by the macro.
SourceLocation FixLocation = Range.getBegin();
// Get the spelling location for performing the fix. This is necessary because
// macros can map the same spelling location to different source locations,
// and we only want to fix the token once, before it is expanded by the macro.
SourceLocation FixLocation = UsageRange.getBegin();
FixLocation = SourceMgr.getSpellingLoc(FixLocation);
if (FixLocation.isInvalid())
return;
return {NamingCheckFailures.end(), false};

auto EmplaceResult = NamingCheckFailures.try_emplace(FailureId);
NamingCheckFailure &Failure = EmplaceResult.first->second;

// Try to insert the identifier location in the Usages map, and bail out if it
// is already in there
RenamerClangTidyCheck::NamingCheckFailure &Failure =
NamingCheckFailures[Decl];
if (!Failure.RawUsageLocs.insert(FixLocation).second)
return;
return EmplaceResult;

if (!Failure.shouldFix())
return;
if (Failure.FixStatus != RenamerClangTidyCheck::ShouldFixStatus::ShouldFix)
return EmplaceResult;

if (SourceMgr.isWrittenInScratchSpace(FixLocation))
Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;

if (!utils::rangeCanBeFixed(Range, &SourceMgr))
if (!utils::rangeCanBeFixed(UsageRange, &SourceMgr))
Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;

return EmplaceResult;
}

void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl, SourceRange Range,
void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl,
SourceRange UsageRange,
const SourceManager &SourceMgr) {
// Don't keep track for non-identifier names.
auto *II = Decl->getIdentifier();
if (!II)
if (hasNoName(Decl))
return;

// Ignore ClassTemplateSpecializationDecl which are creating duplicate
// replacements with CXXRecordDecl.
if (isa<ClassTemplateSpecializationDecl>(Decl))
return;
if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
if (const CXXMethodDecl *Overridden = getOverrideMethod(Method))
Decl = Overridden;
}
Decl = cast<NamedDecl>(Decl->getCanonicalDecl());
return addUsage(
RenamerClangTidyCheck::NamingCheckId(Decl->getLocation(), II->getName()),
Range, SourceMgr);
}

void RenamerClangTidyCheck::checkNamedDecl(const NamedDecl *Decl,
const SourceManager &SourceMgr) {
std::optional<FailureInfo> MaybeFailure = getDeclFailureInfo(Decl, SourceMgr);
// We don't want to create a failure for every NamedDecl we find. Ideally
// there is just one NamedDecl in every group of "related" NamedDecls that
// becomes the failure. This NamedDecl and all of its related NamedDecls
// become usages. E.g. Since NamedDecls are Redeclarable, only the canonical
// NamedDecl becomes the failure and all redeclarations become usages.
const NamedDecl *FailureDecl = getFailureForNamedDecl(Decl);

std::optional<FailureInfo> MaybeFailure =
getDeclFailureInfo(FailureDecl, SourceMgr);
if (!MaybeFailure)
return;

FailureInfo &Info = *MaybeFailure;
NamingCheckFailure &Failure =
NamingCheckFailures[NamingCheckId(Decl->getLocation(), Decl->getName())];
SourceRange Range =
DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
.getSourceRange();

const IdentifierTable &Idents = Decl->getASTContext().Idents;
auto CheckNewIdentifier = Idents.find(Info.Fixup);
NamingCheckId FailureId(FailureDecl->getLocation(), FailureDecl->getName());

auto [FailureIter, NewFailure] = addUsage(FailureId, UsageRange, SourceMgr);

if (FailureIter == NamingCheckFailures.end()) {
// Nothing to do if the usage wasn't accepted.
return;
}
if (!NewFailure) {
// FailureInfo has already been provided.
return;
}

// Update the stored failure with info regarding the FailureDecl.
NamingCheckFailure &Failure = FailureIter->second;
Failure.Info = std::move(*MaybeFailure);

// Don't overwritte the failure status if it was already set.
if (!Failure.shouldFix()) {
return;
}
const IdentifierTable &Idents = FailureDecl->getASTContext().Idents;
auto CheckNewIdentifier = Idents.find(Failure.Info.Fixup);
if (CheckNewIdentifier != Idents.end()) {
const IdentifierInfo *Ident = CheckNewIdentifier->second;
if (Ident->isKeyword(getLangOpts()))
Failure.FixStatus = ShouldFixStatus::ConflictsWithKeyword;
else if (Ident->hasMacroDefinition())
Failure.FixStatus = ShouldFixStatus::ConflictsWithMacroDefinition;
} else if (!isValidAsciiIdentifier(Info.Fixup)) {
} else if (!isValidAsciiIdentifier(Failure.Info.Fixup)) {
Failure.FixStatus = ShouldFixStatus::FixInvalidIdentifier;
}

Failure.Info = std::move(Info);
addUsage(Decl, Range, SourceMgr);
}

void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
Expand Down
14 changes: 8 additions & 6 deletions clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,9 @@ class RenamerClangTidyCheck : public ClangTidyCheck {
void expandMacro(const Token &MacroNameTok, const MacroInfo *MI,
const SourceManager &SourceMgr);

void addUsage(const RenamerClangTidyCheck::NamingCheckId &Decl,
SourceRange Range, const SourceManager &SourceMgr);

/// Convenience method when the usage to be added is a NamedDecl.
void addUsage(const NamedDecl *Decl, SourceRange Range,
const SourceManager &SourceMgr);

void checkNamedDecl(const NamedDecl *Decl, const SourceManager &SourceMgr);

protected:
/// Overridden by derived classes, returns information about if and how a Decl
/// failed the check. A 'std::nullopt' result means the Decl did not fail the
Expand Down Expand Up @@ -158,6 +152,14 @@ class RenamerClangTidyCheck : public ClangTidyCheck {
const NamingCheckFailure &Failure) const = 0;

private:
// Manage additions to the Failure/usage map
//
// return the result of NamingCheckFailures::try_emplace() if the usage was
// accepted.
std::pair<NamingCheckFailureMap::iterator, bool>
addUsage(const RenamerClangTidyCheck::NamingCheckId &FailureId,
SourceRange UsageRange, const SourceManager &SourceMgr);

NamingCheckFailureMap NamingCheckFailures;
const bool AggressiveDependentMemberLookup;
};
Expand Down
4 changes: 3 additions & 1 deletion clang-tools-extra/clangd/Preamble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,9 @@ void PreamblePatch::apply(CompilerInvocation &CI) const {
// no guarantees around using arbitrary options when reusing PCHs, and
// different target opts can result in crashes, see
// ParsedASTTest.PreambleWithDifferentTarget.
CI.TargetOpts = Baseline->TargetOpts;
// Make sure this is a deep copy, as the same Baseline might be used
// concurrently.
*CI.TargetOpts = *Baseline->TargetOpts;

// No need to map an empty file.
if (PatchContents.empty())
Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/clangd/index/CanonicalIncludes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ namespace {
const std::pair<llvm::StringRef, llvm::StringRef> IncludeMappings[] = {
{"include/__stdarg___gnuc_va_list.h", "<cstdarg>"},
{"include/__stdarg___va_copy.h", "<cstdarg>"},
{"include/__stdarg_header_macro.h", "<cstdarg>"},
{"include/__stdarg_va_arg.h", "<cstdarg>"},
{"include/__stdarg_va_copy.h", "<cstdarg>"},
{"include/__stdarg_va_list.h", "<cstdarg>"},
{"include/__stddef_header_macro.h", "<cstddef>"},
{"include/__stddef_max_align_t.h", "<cstddef>"},
{"include/__stddef_null.h", "<cstddef>"},
{"include/__stddef_nullptr_t.h", "<cstddef>"},
Expand Down
5 changes: 1 addition & 4 deletions clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,10 +642,7 @@ TEST_F(TargetDeclTest, RewrittenBinaryOperator) {
bool x = (Foo(1) [[!=]] Foo(2));
)cpp";
EXPECT_DECLS("CXXRewrittenBinaryOperator",
{"std::strong_ordering operator<=>(const Foo &) const = default",
Rel::TemplatePattern},
{"bool operator==(const Foo &) const noexcept = default",
Rel::TemplateInstantiation});
{"bool operator==(const Foo &) const noexcept = default"});
}

TEST_F(TargetDeclTest, FunctionTemplate) {
Expand Down
17 changes: 15 additions & 2 deletions clang-tools-extra/clangd/unittests/HoverTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,19 @@ class Foo final {})cpp";
// Bindings are in theory public members of an anonymous struct.
HI.AccessSpecifier = "public";
}},
{// Don't crash on invalid decl with invalid init expr.
R"cpp(
Unknown [[^abc]] = invalid;
// error-ok
)cpp",
[](HoverInfo &HI) {
HI.Name = "abc";
HI.Kind = index::SymbolKind::Variable;
HI.NamespaceScope = "";
HI.Definition = "int abc = <recovery - expr>()";
HI.Type = "int";
HI.AccessSpecifier = "public";
}},
{// Extra info for function call.
R"cpp(
void fun(int arg_a, int &arg_b) {};
Expand Down Expand Up @@ -3078,7 +3091,7 @@ TEST(Hover, All) {
HI.NamespaceScope = "";
HI.Definition =
"bool operator==(const Foo &) const noexcept = default";
HI.Documentation = "Foo spaceship";
HI.Documentation = "";
}},
};

Expand Down Expand Up @@ -3881,7 +3894,7 @@ TEST(Hover, SpaceshipTemplateNoCrash) {
TU.ExtraArgs.push_back("-std=c++20");
auto AST = TU.build();
auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
EXPECT_EQ(HI->Documentation, "Foo bar baz");
EXPECT_EQ(HI->Documentation, "");
}

TEST(Hover, ForwardStructNoCrash) {
Expand Down
14 changes: 14 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ Changes in existing checks
- Improved :doc:`google-runtime-int <clang-tidy/checks/google/runtime-int>`
check performance through optimizations.

- Improved :doc:`hicpp-signed-bitwise <clang-tidy/checks/hicpp/signed-bitwise>`
check by ignoring false positives involving positive integer literals behind
implicit casts when `IgnorePositiveIntegerLiterals` is enabled.

- Improved :doc:`hicpp-ignored-remove-result <clang-tidy/checks/hicpp/ignored-remove-result>`
check by ignoring other functions with same prefixes as the target specific
functions.
Expand Down Expand Up @@ -348,11 +352,21 @@ Changes in existing checks
<clang-tidy/checks/readability/redundant-inline-specifier>` check to properly
emit warnings for static data member with an in-class initializer.

- Improved :doc:`readability-static-accessed-through-instance
<clang-tidy/checks/readability/static-accessed-through-instance>` check to
support calls to overloaded operators as base expression and provide fixes to
expressions with side-effects.

- Improved :doc:`readability-static-definition-in-anonymous-namespace
<clang-tidy/checks/readability/static-definition-in-anonymous-namespace>`
check by resolving fix-it overlaps in template code by disregarding implicit
instances.

- Improved :doc:`readability-string-compare
<clang-tidy/checks/readability/string-compare>` check to also detect
usages of ``std::string_view::compare``. Added a `StringLikeClasses` option
to detect usages of ``compare`` method in custom string-like classes.

Removed checks
^^^^^^^^^^^^^^

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Options

.. option:: PrintfLikeFunctions

A semicolon-separated list of (fully qualified) extra function names to
A semicolon-separated list of (fully qualified) function names to
replace, with the requirement that the first parameter contains the
printf-style format string and the arguments to be formatted follow
immediately afterwards. If neither this option nor
Expand All @@ -128,7 +128,7 @@ Options

.. option:: FprintfLikeFunctions

A semicolon-separated list of (fully qualified) extra function names to
A semicolon-separated list of (fully qualified) function names to
replace, with the requirement that the first parameter is retained, the
second parameter contains the printf-style format string and the
arguments to be formatted follow immediately afterwards. If neither this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ is changed to:
C::E1;
C::E2;

The `--fix` commandline option provides default support for safe fixes, whereas
`--fix-notes` enables fixes that may replace expressions with side effects,
potentially altering the program's behavior.
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ recommended to avoid the risk of incorrect interpretation of the return value
and to simplify the code. The string equality and inequality operators can
also be faster than the ``compare`` method due to early termination.

Examples:
Example
-------

.. code-block:: c++

// The same rules apply to std::string_view.
std::string str1{"a"};
std::string str2{"b"};

Expand Down Expand Up @@ -50,5 +52,36 @@ Examples:
}

The above code examples show the list of if-statements that this check will
give a warning for. All of them uses ``compare`` to check if equality or
give a warning for. All of them use ``compare`` to check equality or
inequality of two strings instead of using the correct operators.

Options
-------

.. option:: StringLikeClasses

A string containing semicolon-separated names of string-like classes.
By default contains only ``::std::basic_string``
and ``::std::basic_string_view``. If a class from this list has
a ``compare`` method similar to that of ``std::string``, it will be checked
in the same way.

Example
^^^^^^^

.. code-block:: c++

struct CustomString {
public:
int compare (const CustomString& other) const;
}

CustomString str1;
CustomString str2;

// use str1 != str2 instead.
if (str1.compare(str2)) {
}

If `StringLikeClasses` contains ``CustomString``, the check will suggest
replacing ``compare`` with equality operator.
10 changes: 10 additions & 0 deletions clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ struct basic_string_view {
constexpr bool starts_with(C ch) const noexcept;
constexpr bool starts_with(const C* s) const;

constexpr int compare(basic_string_view sv) const noexcept;

static constexpr size_t npos = -1;
};

Expand All @@ -132,6 +134,14 @@ bool operator==(const std::wstring&, const std::wstring&);
bool operator==(const std::wstring&, const wchar_t*);
bool operator==(const wchar_t*, const std::wstring&);

bool operator==(const std::string_view&, const std::string_view&);
bool operator==(const std::string_view&, const char*);
bool operator==(const char*, const std::string_view&);

bool operator!=(const std::string_view&, const std::string_view&);
bool operator!=(const std::string_view&, const char*);
bool operator!=(const char*, const std::string_view&);

size_t strlen(const char* str);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
// RUN: %check_clang_tidy %s bugprone-return-const-ref-from-parameter %t
// RUN: %check_clang_tidy %s bugprone-return-const-ref-from-parameter %t -- -- -fno-delayed-template-parsing

using T = int;
using TConst = int const;
using TConstRef = int const&;

template <typename T>
struct Wrapper { Wrapper(T); };

template <typename T>
struct Identity { using type = T; };

template <typename T>
struct ConstRef { using type = const T&; };

namespace invalid {

int const &f1(int const &a) { return a; }
Expand All @@ -18,8 +27,59 @@ int const &f3(TConstRef a) { return a; }
int const &f4(TConst &a) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter

template <typename T>
const T& tf1(const T &a) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter

template <typename T>
const T& itf1(const T &a) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: returning a constant reference parameter

template <typename T>
typename ConstRef<T>::type itf2(const T &a) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter

template <typename T>
typename ConstRef<T>::type itf3(typename ConstRef<T>::type a) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:72: warning: returning a constant reference parameter

template <typename T>
const T& itf4(typename ConstRef<T>::type a) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter

void instantiate(const int &param, const float &paramf, int &mut_param, float &mut_paramf) {
itf1(0);
itf1(param);
itf1(paramf);
itf2(0);
itf2(param);
itf2(paramf);
itf3<int>(0);
itf3<int>(param);
itf3<float>(paramf);
itf4<int>(0);
itf4<int>(param);
itf4<float>(paramf);
}

struct C {
const C& foo(const C&c) { return c; }
// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: returning a constant reference parameter
};

} // namespace invalid

namespace false_negative_because_dependent_and_not_instantiated {
template <typename T>
typename ConstRef<T>::type tf2(const T &a) { return a; }

template <typename T>
typename ConstRef<T>::type tf3(typename ConstRef<T>::type a) { return a; }

template <typename T>
const T& tf4(typename ConstRef<T>::type a) { return a; }
} // false_negative_because_dependent_and_not_instantiated

namespace valid {

int const &f1(int &a) { return a; }
Expand All @@ -28,4 +88,58 @@ int const &f2(int &&a) { return a; }

int f1(int const &a) { return a; }

template <typename T>
T tf1(T a) { return a; }

template <typename T>
T tf2(const T a) { return a; }

template <typename T>
T tf3(const T &a) { return a; }

template <typename T>
Identity<T>::type tf4(const T &a) { return a; }

template <typename T>
T itf1(T a) { return a; }

template <typename T>
T itf2(const T a) { return a; }

template <typename T>
T itf3(const T &a) { return a; }

template <typename T>
Wrapper<T> itf4(const T& a) { return a; }

template <typename T>
const T& itf5(T& a) { return a; }

template <typename T>
T itf6(T& a) { return a; }

void instantiate(const int &param, const float &paramf, int &mut_param, float &mut_paramf) {
itf1(0);
itf1(param);
itf1(paramf);
itf2(0);
itf2(param);
itf2(paramf);
itf3(0);
itf3(param);
itf3(paramf);
itf2(0);
itf2(param);
itf2(paramf);
itf3(0);
itf3(param);
itf3(paramf);
itf4(param);
itf4(paramf);
itf5(mut_param);
itf5(mut_paramf);
itf6(mut_param);
itf6(mut_paramf);
}

} // namespace valid
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ void examples() {
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use of a signed integer operand with a binary bitwise operator

unsigned URes2 = URes << 1; //Ok
unsigned URes3 = URes & 1; //Ok

int IResult;
IResult = 10 & 2; //Ok
Expand All @@ -21,6 +22,8 @@ void examples() {
IResult = Int << 1;
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
IResult = ~0; //Ok
IResult = -1 & 1;
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator [hicpp-signed-bitwise]
}

enum EnumConstruction {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- -- -isystem %S/Inputs/static-accessed-through-instance
// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- --fix-notes -- -isystem %S/Inputs/static-accessed-through-instance
#include <__clang_cuda_builtin_vars.h>

enum OutEnum {
Expand Down Expand Up @@ -47,7 +47,8 @@ C &f(int, int, int, int);
void g() {
f(1, 2, 3, 4).x;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance]
// CHECK-FIXES: {{^}} f(1, 2, 3, 4).x;{{$}}
// CHECK-MESSAGES: :[[@LINE-2]]:3: note: member base expression may carry some side effects
// CHECK-FIXES: {{^}} C::x;{{$}}
}

int i(int &);
Expand All @@ -59,20 +60,23 @@ int k(bool);
void f(C c) {
j(i(h().x));
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: static member
// CHECK-FIXES: {{^}} j(i(h().x));{{$}}
// CHECK-MESSAGES: :[[@LINE-2]]:7: note: member base expression may carry some side effects
// CHECK-FIXES: {{^}} j(i(C::x));{{$}}

// The execution of h() depends on the return value of a().
j(k(a() && h().x));
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static member
// CHECK-FIXES: {{^}} j(k(a() && h().x));{{$}}
// CHECK-MESSAGES: :[[@LINE-2]]:14: note: member base expression may carry some side effects
// CHECK-FIXES: {{^}} j(k(a() && C::x));{{$}}

if ([c]() {
c.ns();
return c;
}().x == 15)
;
// CHECK-MESSAGES: :[[@LINE-5]]:7: warning: static member
// CHECK-FIXES: {{^}} if ([c]() {{{$}}
// CHECK-MESSAGES: :[[@LINE-6]]:7: note: member base expression may carry some side effects
// CHECK-FIXES: {{^}} if (C::x == 15){{$}}
}

// Nested specifiers
Expand Down Expand Up @@ -261,8 +265,11 @@ struct Qptr {
};

int func(Qptr qp) {
qp->y = 10; // OK, the overloaded operator might have side-effects.
qp->K = 10; //
qp->y = 10;
qp->K = 10;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance]
// CHECK-MESSAGES: :[[@LINE-2]]:3: note: member base expression may carry some side effects
// CHECK-FIXES: {{^}} Q::K = 10;
}

namespace {
Expand Down Expand Up @@ -380,3 +387,20 @@ namespace PR51861 {
// CHECK-FIXES: {{^}} PR51861::Foo::getBar();{{$}}
}
}

namespace PR75163 {
struct Static {
static void call();
};

struct Ptr {
Static* operator->();
};

void test(Ptr& ptr) {
ptr->call();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: static member accessed through instance [readability-static-accessed-through-instance]
// CHECK-MESSAGES: :[[@LINE-2]]:5: note: member base expression may carry some side effects
// CHECK-FIXES: {{^}} PR75163::Static::call();{{$}}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %check_clang_tidy %s readability-string-compare %t -- -config='{CheckOptions: {readability-string-compare.StringLikeClasses: "CustomStringTemplateBase;CustomStringNonTemplateBase"}}' -- -isystem %clang_tidy_headers
#include <string>

struct CustomStringNonTemplateBase {
int compare(const CustomStringNonTemplateBase& Other) const {
return 123; // value is not important for check
}
};

template <typename T>
struct CustomStringTemplateBase {
int compare(const CustomStringTemplateBase& Other) const {
return 123;
}
};

struct CustomString1 : CustomStringNonTemplateBase {};
struct CustomString2 : CustomStringTemplateBase<char> {};

void CustomStringClasses() {
std::string_view sv1("a");
std::string_view sv2("b");
if (sv1.compare(sv2)) { // No warning - if a std class is not listed in StringLikeClasses, it won't be checked.
}

CustomString1 custom1;
if (custom1.compare(custom1)) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]

CustomString2 custom2;
if (custom2.compare(custom2)) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,27 @@ void Test() {
if (str1.compare(comp())) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;

std::string_view sv1("a");
std::string_view sv2("b");
if (sv1.compare(sv2)) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]
}

struct DerivedFromStdString : std::string {};

void TestDerivedClass() {
DerivedFromStdString derived;
if (derived.compare(derived)) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]
}

void Valid() {
std::string str1("a", 1);
std::string str2("b", 1);

if (str1 == str2) {
}
if (str1 != str2) {
Expand All @@ -96,4 +112,11 @@ void Valid() {
}
if (str1.compare(str2) == -1) {
}

std::string_view sv1("a");
std::string_view sv2("b");
if (sv1 == sv2) {
}
if (sv1.compare(sv2) > 0) {
}
}
2 changes: 2 additions & 0 deletions clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ endif()


if( CLANG_INCLUDE_TESTS )
find_package(Perl)

add_subdirectory(unittests)
list(APPEND CLANG_TEST_DEPS ClangUnitTests)
list(APPEND CLANG_TEST_PARAMS
Expand Down
40 changes: 37 additions & 3 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,8 @@ the configuration (without a prefix: ``Auto``).

**AlignConsecutiveShortCaseStatements** (``ShortCaseStatementsAlignmentStyle``) :versionbadge:`clang-format 17` :ref:`¶ <AlignConsecutiveShortCaseStatements>`
Style of aligning consecutive short case labels.
Only applies if ``AllowShortCaseLabelsOnASingleLine`` is ``true``.
Only applies if ``AllowShortCaseExpressionOnASingleLine`` or
``AllowShortCaseLabelsOnASingleLine`` is ``true``.


.. code-block:: yaml
Expand Down Expand Up @@ -935,8 +936,26 @@ the configuration (without a prefix: ``Auto``).
default: return "";
}

* ``bool AlignCaseColons`` Whether aligned case labels are aligned on the colon, or on the
, or on the tokens after the colon.
* ``bool AlignCaseArrows`` Whether to align the case arrows when aligning short case expressions.

.. code-block:: java

true:
i = switch (day) {
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> 0;
};

false:
i = switch (day) {
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> 0;
};

* ``bool AlignCaseColons`` Whether aligned case labels are aligned on the colon, or on the tokens
after the colon.

.. code-block:: c++

Expand Down Expand Up @@ -1692,6 +1711,21 @@ the configuration (without a prefix: ``Auto``).



.. _AllowShortCaseExpressionOnASingleLine:

**AllowShortCaseExpressionOnASingleLine** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ <AllowShortCaseExpressionOnASingleLine>`
Whether to merge a short switch labeled rule into a single line.

.. code-block:: java

true: false:
switch (a) { vs. switch (a) {
case 1 -> 1; case 1 ->
default -> 0; 1;
}; default ->
0;
};

.. _AllowShortCaseLabelsOnASingleLine:

**AllowShortCaseLabelsOnASingleLine** (``Boolean``) :versionbadge:`clang-format 3.6` :ref:`¶ <AllowShortCaseLabelsOnASingleLine>`
Expand Down
12 changes: 10 additions & 2 deletions clang/docs/ClangOffloadBundler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ Where:
object as a data section with the name ``.hip_fatbin``.

hipv4 Offload code object for the HIP language. Used for AMD GPU
code objects with at least ABI version V4 when the
code objects with at least ABI version V4 and above when the
``clang-offload-bundler`` is used to create a *fat binary*
to be loaded by the HIP runtime. The fat binary can be
loaded directly from a file, or be embedded in the host code
Expand All @@ -254,6 +254,14 @@ Where:
openmp Offload code object for the OpenMP language extension.
============= ==============================================================

Note: The distinction between the `hip` and `hipv4` offload kinds is historically based.
Originally, these designations might have indicated different versions of the
code object ABI. However, as the system has evolved, the ABI version is now embedded
directly within the code object itself, making these historical distinctions irrelevant
during the unbundling process. Consequently, `hip` and `hipv4` are treated as compatible
in current implementations, facilitating interchangeable handling of code objects
without differentiation based on offload kind.

**target-triple**
The target triple of the code object. See `Target Triple
<https://clang.llvm.org/docs/CrossCompilation.html#target-triple>`_.
Expand Down Expand Up @@ -295,7 +303,7 @@ Compatibility Rules for Bundle Entry ID
A code object, specified using its Bundle Entry ID, can be loaded and
executed on a target processor, if:

* Their offload kinds are the same.
* Their offload kinds are the same or comptible.
* Their target triples are compatible.
* Their Target IDs are compatible as defined in :ref:`compatibility-target-id`.

Expand Down
6 changes: 5 additions & 1 deletion clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in
T __builtin_elementwise_ceil(T x) return the smallest integral value greater than or equal to x floating point types
T __builtin_elementwise_sin(T x) return the sine of x interpreted as an angle in radians floating point types
T __builtin_elementwise_cos(T x) return the cosine of x interpreted as an angle in radians floating point types
T __builtin_elementwise_tan(T x) return the tangent of x interpreted as an angle in radians floating point types
T __builtin_elementwise_floor(T x) return the largest integral value less than or equal to x floating point types
T __builtin_elementwise_log(T x) return the natural logarithm of x floating point types
T __builtin_elementwise_log2(T x) return the base 2 logarithm of x floating point types
Expand Down Expand Up @@ -1661,8 +1662,11 @@ The following type trait primitives are supported by Clang. Those traits marked
``T`` from ``U`` is ill-formed.
Deprecated, use ``__reference_constructs_from_temporary``.
* ``__reference_constructs_from_temporary(T, U)`` (C++)
Returns true if a reference ``T`` can be constructed from a temporary of type
Returns true if a reference ``T`` can be direct-initialized from a temporary of type
a non-cv-qualified ``U``.
* ``__reference_converts_from_temporary(T, U)`` (C++)
Returns true if a reference ``T`` can be copy-initialized from a temporary of type
a non-cv-qualified ``U``.
* ``__underlying_type`` (C++, GNU, Microsoft)

In addition, the following expression traits are supported:
Expand Down
29 changes: 29 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ ABI Changes in This Version
returning a class in a register. This affects some uses of std::pair.
(#GH86384).

- Fixed Microsoft calling convention when returning classes that have a deleted
copy assignment operator. Such a class should be returned indirectly.

AST Dumping Potentially Breaking Changes
----------------------------------------

Expand Down Expand Up @@ -179,6 +182,9 @@ C++23 Feature Support

- Implemented `P2448R2: Relaxing some constexpr restrictions <https://wg21.link/P2448R2>`_.

- Added a ``__reference_converts_from_temporary`` builtin, completing the necessary compiler support for
`P2255R2: Type trait to determine if a reference binds to a temporary <https://wg21.link/P2255R2>`_.

C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -303,6 +309,11 @@ New Compiler Flags
allow late parsing certain attributes in specific contexts where they would
not normally be late parsed.

- ``-fseparate-named-sections`` uses separate unique sections for global
symbols in named special sections (i.e. symbols annotated with
``__attribute__((section(...)))``. This enables linker GC to collect unused
symbols without having to use a per-symbol section.

Deprecated Compiler Flags
-------------------------

Expand Down Expand Up @@ -681,6 +692,20 @@ Bug Fixes to C++ Support
whose type is `decltype(auto)`. Fixes (#GH68885).
- Clang now correctly treats the noexcept-specifier of a friend function to be a complete-class context.
- Fix an assertion failure when parsing an invalid members of an anonymous class. (#GH85447)
- Fixed a misuse of ``UnresolvedLookupExpr`` for ill-formed templated expressions. Fixes (#GH48673), (#GH63243)
and (#GH88832).
- Clang now defers all substitution into the exception specification of a function template specialization
until the noexcept-specifier is instantiated.
- Fix a crash when an implicitly declared ``operator==`` function with a trailing requires-clause has its
constraints compared to that of another declaration.
- Fix a bug where explicit specializations of member functions/function templates would have substitution
performed incorrectly when checking constraints. Fixes (#GH90349).
- Clang now allows constrained member functions to be explicitly specialized for an implicit instantiation
of a class template.
- Fix a C++23 bug in implementation of P2564R3 which evaluates immediate invocations in place
within initializers for variables that are usable in constant expressions or are constant
initialized, rather than evaluating them as a part of the larger manifestly constant evaluated
expression.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -780,6 +805,7 @@ CUDA/HIP Language Changes

CUDA Support
^^^^^^^^^^^^
- Clang now supports CUDA SDK up to 12.4

AIX Support
^^^^^^^^^^^
Expand Down Expand Up @@ -832,6 +858,9 @@ clang-format
``BreakTemplateDeclarations``.
- ``AlwaysBreakAfterReturnType`` is deprecated and renamed to
``BreakAfterReturnType``.
- Handles Java ``switch`` expressions.
- Adds ``AllowShortCaseExpressionOnASingleLine`` option.
- Adds ``AlignCaseArrows`` suboption to ``AlignConsecutiveShortCaseStatements``.

libclang
--------
Expand Down
1,215 changes: 604 additions & 611 deletions clang/docs/StandardCPlusPlusModules.rst

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3504,7 +3504,7 @@ Differences between ``*17`` and ``*23`` modes:
- ``nullptr`` and ``nullptr_t`` are supported, only in ``*23`` mode.
- ``ATOMIC_VAR_INIT`` is removed from ``*23`` mode.
- ``bool``, ``true``, ``false``, ``alignas``, ``alignof``, ``static_assert``,
and ``thread_local` are now first-class keywords, only in ``*23`` mode.
and ``thread_local`` are now first-class keywords, only in ``*23`` mode.
- ``typeof`` and ``typeof_unqual`` are supported, only ``*23`` mode.
- Bit-precise integers (``_BitInt(N)``) are supported by default in ``*23``
mode, and as an extension in ``*17`` and earlier modes.
Expand Down
3 changes: 2 additions & 1 deletion clang/docs/tools/clang-formatted-files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -632,11 +632,12 @@ clang/unittests/Analysis/FlowSensitive/MapLatticeTest.cpp
clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp
clang/unittests/Analysis/FlowSensitive/MultiVarConstantPropagationTest.cpp
clang/unittests/Analysis/FlowSensitive/SingleVarConstantPropagationTest.cpp
clang/unittests/Analysis/FlowSensitive/SolverTest.cpp
clang/unittests/Analysis/FlowSensitive/SolverTest.h
clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
clang/unittests/Analysis/FlowSensitive/WatchedLiteralsSolverTest.cpp
clang/unittests/AST/ASTImporterFixtures.cpp
clang/unittests/AST/ASTImporterFixtures.h
clang/unittests/AST/ASTImporterObjCTest.cpp
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
CanQualType BFloat16Ty;
CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnresolvedTemplateTy,
UnknownAnyTy;
CanQualType BuiltinFnTy;
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/BuiltinTypes.def
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,9 @@ PLACEHOLDER_TYPE(Overload, OverloadTy)
// x->foo # if only contains non-static members
PLACEHOLDER_TYPE(BoundMember, BoundMemberTy)

// The type of an unresolved template. Used in UnresolvedLookupExpr.
PLACEHOLDER_TYPE(UnresolvedTemplate, UnresolvedTemplateTy)

// The type of an expression which refers to a pseudo-object,
// such as those introduced by Objective C's @property or
// VS.NET's __property declarations. A placeholder type. The
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5049,6 +5049,11 @@ static constexpr StringRef getOpenMPVariantManglingSeparatorStr() {
return "$ompvariant";
}

/// Returns whether the given FunctionDecl has an __arm[_locally]_streaming
/// attribute.
bool IsArmStreamingFunction(const FunctionDecl *FD,
bool IncludeLocallyStreaming);

} // namespace clang

#endif // LLVM_CLANG_AST_DECL_H
22 changes: 22 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -3163,8 +3163,30 @@ class OverloadExpr : public Expr {
/// This arises in several ways:
/// * we might be waiting for argument-dependent lookup;
/// * the name might resolve to an overloaded function;
/// * the name might resolve to a non-function template; for example, in the
/// following snippet, the return expression of the member function
/// 'foo()' might remain unresolved until instantiation:
///
/// \code
/// struct P {
/// template <class T> using I = T;
/// };
///
/// struct Q {
/// template <class T> int foo() {
/// return T::template I<int>;
/// }
/// };
/// \endcode
///
/// ...which is distinct from modeling function overloads, and therefore we use
/// a different builtin type 'UnresolvedTemplate' to avoid confusion. This is
/// done in Sema::BuildTemplateIdExpr.
///
/// and eventually:
/// * the lookup might have included a function template.
/// * the unresolved template gets transformed in an instantiation or gets
/// diagnosed for its direct use.
///
/// These never include UnresolvedUsingValueDecls, which are always class
/// members and therefore appear only in UnresolvedMemberLookupExprs.
Expand Down
97 changes: 95 additions & 2 deletions clang/include/clang/AST/OpenACCClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ class OpenACCClause {
protected:
OpenACCClause(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation EndLoc)
: Kind(K), Location(BeginLoc, EndLoc) {}
: Kind(K), Location(BeginLoc, EndLoc) {
assert(!BeginLoc.isInvalid() && !EndLoc.isInvalid() &&
"Begin and end location must be valid for OpenACCClause");
}

public:
OpenACCClauseKind getClauseKind() const { return Kind; }
Expand Down Expand Up @@ -189,6 +192,46 @@ class OpenACCClauseWithExprs : public OpenACCClauseWithParams {
}
};

// Represents the 'devnum' and expressions lists for the 'wait' clause.
class OpenACCWaitClause final
: public OpenACCClauseWithExprs,
public llvm::TrailingObjects<OpenACCWaitClause, Expr *> {
SourceLocation QueuesLoc;
OpenACCWaitClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *DevNumExpr, SourceLocation QueuesLoc,
ArrayRef<Expr *> QueueIdExprs, SourceLocation EndLoc)
: OpenACCClauseWithExprs(OpenACCClauseKind::Wait, BeginLoc, LParenLoc,
EndLoc),
QueuesLoc(QueuesLoc) {
// The first element of the trailing storage is always the devnum expr,
// whether it is used or not.
std::uninitialized_copy(&DevNumExpr, &DevNumExpr + 1,
getTrailingObjects<Expr *>());
std::uninitialized_copy(QueueIdExprs.begin(), QueueIdExprs.end(),
getTrailingObjects<Expr *>() + 1);
setExprs(
MutableArrayRef(getTrailingObjects<Expr *>(), QueueIdExprs.size() + 1));
}

public:
static OpenACCWaitClause *Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *DevNumExpr,
SourceLocation QueuesLoc,
ArrayRef<Expr *> QueueIdExprs,
SourceLocation EndLoc);

bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); }
SourceLocation getQueuesLoc() const { return QueuesLoc; }
bool hasDevNumExpr() const { return getExprs()[0]; }
Expr *getDevNumExpr() const { return getExprs()[0]; }
llvm::ArrayRef<Expr *> getQueueIdExprs() {
return OpenACCClauseWithExprs::getExprs().drop_front();
}
llvm::ArrayRef<Expr *> getQueueIdExprs() const {
return OpenACCClauseWithExprs::getExprs().drop_front();
}
};

class OpenACCNumGangsClause final
: public OpenACCClauseWithExprs,
public llvm::TrailingObjects<OpenACCNumGangsClause, Expr *> {
Expand Down Expand Up @@ -227,7 +270,8 @@ class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs {
SourceLocation EndLoc)
: OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc),
IntExpr(IntExpr) {
setExprs(MutableArrayRef<Expr *>{&this->IntExpr, 1});
if (IntExpr)
setExprs(MutableArrayRef<Expr *>{&this->IntExpr, 1});
}

public:
Expand Down Expand Up @@ -260,6 +304,17 @@ class OpenACCVectorLengthClause : public OpenACCClauseWithSingleIntExpr {
Expr *IntExpr, SourceLocation EndLoc);
};

class OpenACCAsyncClause : public OpenACCClauseWithSingleIntExpr {
OpenACCAsyncClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *IntExpr, SourceLocation EndLoc);

public:
static OpenACCAsyncClause *Create(const ASTContext &C,
SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *IntExpr,
SourceLocation EndLoc);
};

/// Represents a clause with one or more 'var' objects, represented as an expr,
/// as its arguments. Var-list is expected to be stored in trailing storage.
/// For now, we're just storing the original expression in its entirety, unlike
Expand Down Expand Up @@ -313,6 +368,44 @@ class OpenACCFirstPrivateClause final
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};

class OpenACCDevicePtrClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCDevicePtrClause, Expr *> {

OpenACCDevicePtrClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::DevicePtr, BeginLoc,
LParenLoc, EndLoc) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}

public:
static OpenACCDevicePtrClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};

class OpenACCAttachClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCAttachClause, Expr *> {

OpenACCAttachClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Attach, BeginLoc, LParenLoc,
EndLoc) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}

public:
static OpenACCAttachClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};

class OpenACCNoCreateClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCNoCreateClause, Expr *> {
Expand Down
5 changes: 2 additions & 3 deletions clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,8 @@ llvm::Expected<llvm::SmallVector<Diagnostic>> diagnoseFunction(
if (!Context)
return Context.takeError();

auto OwnedSolver = std::make_unique<WatchedLiteralsSolver>(MaxSATIterations);
const WatchedLiteralsSolver *Solver = OwnedSolver.get();
DataflowAnalysisContext AnalysisContext(std::move(OwnedSolver));
auto Solver = std::make_unique<WatchedLiteralsSolver>(MaxSATIterations);
DataflowAnalysisContext AnalysisContext(*Solver);
Environment Env(AnalysisContext, FuncDecl);
AnalysisT Analysis = createAnalysis<AnalysisT>(ASTCtx, Env);
llvm::SmallVector<Diagnostic> Diagnostics;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,19 @@ class DataflowAnalysisContext {
DataflowAnalysisContext(std::unique_ptr<Solver> S,
Options Opts = Options{
/*ContextSensitiveOpts=*/std::nullopt,
/*Logger=*/nullptr});
/*Logger=*/nullptr})
: DataflowAnalysisContext(*S, std::move(S), Opts) {}

/// Constructs a dataflow analysis context.
///
/// Requirements:
///
/// `S` must outlive the `DataflowAnalysisContext`.
DataflowAnalysisContext(Solver &S, Options Opts = Options{
/*ContextSensitiveOpts=*/std::nullopt,
/*Logger=*/nullptr})
: DataflowAnalysisContext(S, nullptr, Opts) {}

~DataflowAnalysisContext();

/// Sets a callback that returns the names and types of the synthetic fields
Expand Down Expand Up @@ -209,6 +221,13 @@ class DataflowAnalysisContext {
using DenseMapInfo::isEqual;
};

/// `S` is the solver to use. `OwnedSolver` may be:
/// * Null (in which case `S` is non-onwed and must outlive this object), or
/// * Non-null (in which case it must refer to `S`, and the
/// `DataflowAnalysisContext will take ownership of `OwnedSolver`).
DataflowAnalysisContext(Solver &S, std::unique_ptr<Solver> &&OwnedSolver,
Options Opts);

// Extends the set of modeled field declarations.
void addModeledFields(const FieldSet &Fields);

Expand All @@ -232,7 +251,8 @@ class DataflowAnalysisContext {
Solver::Result::Status::Unsatisfiable;
}

std::unique_ptr<Solver> S;
Solver &S;
std::unique_ptr<Solver> OwnedSolver;
std::unique_ptr<Arena> A;

// Maps from program declarations and statements to storage locations that are
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Analysis/FlowSensitive/Solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class Solver {
///
/// All elements in `Vals` must not be null.
virtual Result solve(llvm::ArrayRef<const Formula *> Vals) = 0;

// Did the solver reach its resource limit?
virtual bool reachedLimit() const = 0;
};

llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Solver::Result &);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ class WatchedLiteralsSolver : public Solver {

Result solve(llvm::ArrayRef<const Formula *> Vals) override;

// The solver reached its maximum number of iterations.
bool reachedLimit() const { return MaxIterations == 0; }
bool reachedLimit() const override { return MaxIterations == 0; }
};

} // namespace dataflow
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -4415,6 +4415,18 @@ def HLSLResourceBinding: InheritableAttr {
let Documentation = [HLSLResourceBindingDocs];
}

def HLSLPackOffset: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"packoffset">];
let LangOpts = [HLSL];
let Args = [IntArgument<"Subcomponent">, IntArgument<"Component">];
let Documentation = [HLSLPackOffsetDocs];
let AdditionalMembers = [{
unsigned getOffset() {
return subcomponent * 4 + component;
}
}];
}

def HLSLSV_DispatchThreadID: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"SV_DispatchThreadID">];
let Subjects = SubjectList<[ParmVar, Field]>;
Expand Down
25 changes: 23 additions & 2 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -5663,11 +5663,12 @@ The ``preserve_none`` calling convention tries to preserve as few general
registers as possible. So all general registers are caller saved registers. It
also uses more general registers to pass arguments. This attribute doesn't
impact floating-point registers (XMMs/YMMs). Floating-point registers still
follow the c calling convention.
follow the c calling convention. ``preserve_none``'s ABI is still unstable, and
may be changed in the future.

- Only RSP and RBP are preserved by callee.

- Register RDI, RSI, RDX, RCX, R8, R9, R11, R12, R13, R14, R15 and RAX now can
- Register R12, R13, R14, R15, RDI, RSI, RDX, RCX, R8, R9, R11, and RAX now can
be used to pass function arguments.
}];
}
Expand Down Expand Up @@ -7407,6 +7408,26 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo
}];
}

def HLSLPackOffsetDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The packoffset attribute is used to change the layout of a cbuffer.
Attribute spelling in HLSL is: ``packoffset( c[Subcomponent][.component] )``.
A subcomponent is a register number, which is an integer. A component is in the form of [.xyzw].

Examples:

.. code-block:: c++

cbuffer A {
float3 a : packoffset(c0.y);
float4 b : packoffset(c4);
}

The full documentation is available here: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-packoffset
}];
}

def HLSLSV_DispatchThreadIDDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,12 @@ def ElementwiseSqrt : Builtin {
let Prototype = "void(...)";
}

def ElementwiseTan : Builtin {
let Spellings = ["__builtin_elementwise_tan"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Prototype = "void(...)";
}

def ElementwiseTrunc : Builtin {
let Spellings = ["__builtin_elementwise_trunc"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/BuiltinsNVPTX.def
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@
#pragma push_macro("PTX81")
#pragma push_macro("PTX82")
#pragma push_macro("PTX83")
#define PTX83 "ptx83"
#pragma push_macro("PTX84")
#define PTX84 "ptx84"
#define PTX83 "ptx83|" PTX84
#define PTX82 "ptx82|" PTX83
#define PTX81 "ptx81|" PTX82
#define PTX80 "ptx80|" PTX81
Expand Down Expand Up @@ -1091,3 +1093,4 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78))
#pragma pop_macro("PTX81")
#pragma pop_macro("PTX82")
#pragma pop_macro("PTX83")
#pragma pop_macro("PTX84")
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/BuiltinsWebAssembly.def
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8, "V8sV16ScV16Sc",
TARGET_BUILTIN(__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4, "V4iV16ScV16ScV4i", "nc", "relaxed-simd")
TARGET_BUILTIN(__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4, "V4fV8UsV8UsV4f", "nc", "relaxed-simd")

// Half-Precision (fp16)
TARGET_BUILTIN(__builtin_wasm_loadf16_f32, "fh*", "nU", "half-precision")
TARGET_BUILTIN(__builtin_wasm_storef16_f32, "vfh*", "n", "half-precision")

// Reference Types builtins
// Some builtins are custom type-checked - see 't' as part of the third argument,
// in which case the argument spec (second argument) is unused.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ CODEGENOPT(UniqueSectionNames, 1, 1) ///< Set for -funique-section-names.
CODEGENOPT(UniqueBasicBlockSectionNames, 1, 1) ///< Set for -funique-basic-block-section-names,
///< Produce unique section names with
///< basic block sections.
CODEGENOPT(SeparateNamedSections, 1, 0) ///< Set for -fseparate-named-sections.
CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX.
CODEGENOPT(XCOFFReadOnlyPointers, 1, 0) ///< Set for -mxcoff-roptr.
CODEGENOPT(AllTocData, 1, 0) ///< AIX -mtocdata
Expand Down Expand Up @@ -308,6 +309,7 @@ CODEGENOPT(UnrollLoops , 1, 0) ///< Control whether loops are unrolled.
CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled.
CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled.
VALUE_CODEGENOPT(UnwindTables, 2, 0) ///< Unwind tables (1) or asynchronous unwind tables (2)
CODEGENOPT(LinkBitcodePostopt, 1, 0) ///< Link builtin bitcodes after optimization pipeline.
CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer.
CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer.
CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate.
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/Cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ enum class CudaVersion {
CUDA_121,
CUDA_122,
CUDA_123,
CUDA_124,
FULLY_SUPPORTED = CUDA_123,
PARTIALLY_SUPPORTED =
CUDA_123, // Partially supported. Proceed with a warning.
CUDA_124, // Partially supported. Proceed with a warning.
NEW = 10000, // Too new. Issue a warning, but allow using it.
};
const char *CudaVersionToString(CudaVersion V);
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ def err_fe_no_pch_in_dir : Error<
"no suitable precompiled header file found in directory '%0'">;
def err_fe_action_not_available : Error<
"action %0 not compiled in">;
def err_fe_invalid_multiple_actions : Error<
"'%0' action ignored; '%1' action specified previously">;
def err_fe_invalid_alignment : Error<
"invalid value '%1' in '%0'; alignment must be a power of 2">;
def err_fe_invalid_exception_model
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,9 @@ def BranchProtection : DiagGroup<"branch-protection">;
// Warnings for HLSL Clang extensions
def HLSLExtension : DiagGroup<"hlsl-extensions">;

// Warning for mix packoffset and non-packoffset.
def HLSLMixPackOffset : DiagGroup<"mix-packoffset">;

// Warnings for DXIL validation
def DXILValidation : DiagGroup<"dxil-validation">;

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1754,5 +1754,7 @@ def err_hlsl_separate_attr_arg_and_number : Error<"wrong argument format for hls
def ext_hlsl_access_specifiers : ExtWarn<
"access specifiers are a clang HLSL extension">,
InGroup<HLSLExtension>;
def err_hlsl_unsupported_component : Error<"invalid component '%0' used; expected 'x', 'y', 'z', or 'w'">;
def err_hlsl_packoffset_invalid_reg : Error<"invalid resource class specifier '%0' for packoffset, expected 'c'">;

} // end of Parser diagnostics
13 changes: 13 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5437,6 +5437,11 @@ def note_function_template_spec_matched : Note<
def err_function_template_partial_spec : Error<
"function template partial specialization is not allowed">;

def err_function_member_spec_ambiguous : Error<
"ambiguous member function specialization %q0 of %q1">;
def note_function_member_spec_matched : Note<
"member function specialization matches %0">;

// C++ Template Instantiation
def err_template_recursion_depth_exceeded : Error<
"recursive template instantiation exceeded maximum depth of %0">,
Expand Down Expand Up @@ -12179,6 +12184,11 @@ def err_hlsl_init_priority_unsupported : Error<
def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
def warn_hlsl_packoffset_mix : Warning<"cannot mix packoffset elements with nonpackoffset elements in a cbuffer">,
InGroup<HLSLMixPackOffset>;
def err_hlsl_packoffset_overlap : Error<"packoffset overlap between %0, %1">;
def err_hlsl_packoffset_cross_reg_boundary : Error<"packoffset cannot cross register boundary">;
def err_hlsl_packoffset_alignment_mismatch : Error<"packoffset at 'y' not match alignment %0 required by %1">;
def err_hlsl_pointers_unsupported : Error<
"%select{pointers|references}0 are unsupported in HLSL">;

Expand Down Expand Up @@ -12337,4 +12347,7 @@ def warn_acc_deprecated_alias_name
: Warning<"OpenACC clause name '%0' is a deprecated clause name and is "
"now an alias for '%1'">,
InGroup<DiagGroup<"openacc-deprecated-clause-alias">>;
def err_acc_var_not_pointer_type
: Error<"expected pointer in '%0' clause, type is %1">;
def note_acc_expected_pointer_var : Note<"expected variable of pointer type">;
} // end of sema component.
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
EXTENSION(swiftcc,
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
clang::TargetInfo::CCCR_OK)
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template t
LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features")

LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
LANGOPT(PointerAuthCalls , 1, 0, "function pointer authentication")
LANGOPT(PointerAuthReturns, 1, 0, "return pointer authentication")
LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")

LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")
Expand Down
5 changes: 1 addition & 4 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -968,10 +968,7 @@ class FPOptionsOverride {
setAllowFPContractAcrossStatement();
}

void setDisallowOptimizations() {
setFPPreciseEnabled(true);
setDisallowFPContract();
}
void setDisallowOptimizations() { setFPPreciseEnabled(true); }

storage_type getAsOpaqueInt() const {
return (static_cast<storage_type>(Options.getAsOpaqueInt())
Expand Down
583 changes: 500 additions & 83 deletions clang/include/clang/Basic/MSP430Target.def

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions clang/include/clang/Basic/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,10 @@ class alignas(8) Module {
/// found on the file system.
SmallVector<UnresolvedHeaderDirective, 1> MissingHeaders;

/// An individual requirement: a feature name and a flag indicating
/// the required state of that feature.
using Requirement = std::pair<std::string, bool>;
struct Requirement {
std::string FeatureName;
bool RequiredState;
};

/// The set of language features required to use this module.
///
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/OpenACCClauses.def
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)
#endif

VISIT_CLAUSE(Async)
VISIT_CLAUSE(Attach)
VISIT_CLAUSE(Copy)
CLAUSE_ALIAS(PCopy, Copy)
CLAUSE_ALIAS(PresentOrCopy, Copy)
Expand All @@ -34,6 +36,7 @@ VISIT_CLAUSE(Create)
CLAUSE_ALIAS(PCreate, Create)
CLAUSE_ALIAS(PresentOrCreate, Create)
VISIT_CLAUSE(Default)
VISIT_CLAUSE(DevicePtr)
VISIT_CLAUSE(FirstPrivate)
VISIT_CLAUSE(If)
VISIT_CLAUSE(NoCreate)
Expand All @@ -43,6 +46,7 @@ VISIT_CLAUSE(Present)
VISIT_CLAUSE(Private)
VISIT_CLAUSE(Self)
VISIT_CLAUSE(VectorLength)
VISIT_CLAUSE(Wait)

#undef VISIT_CLAUSE
#undef CLAUSE_ALIAS
1 change: 1 addition & 0 deletions clang/include/clang/Basic/SourceLocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class SourceLocation {
friend class ASTWriter;
friend class SourceManager;
friend struct llvm::FoldingSetTrait<SourceLocation, void>;
friend class SourceLocationEncoding;

public:
using UIntTy = uint32_t;
Expand Down
126 changes: 126 additions & 0 deletions clang/include/clang/Basic/Target/MSP430/gen-msp430-def.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/env python3
# ===----------------------------------------------------------------------===##
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# ===----------------------------------------------------------------------===##
"""
Script to generate MSP430 definitions from TI's devices.csv

Download the devices.csv from [1] using the link "Header and Support Files".

[1]: https://www.ti.com/tool/MSP430-GCC-OPENSOURCE#downloads
"""
import csv
import sys

DEVICE_COLUMN = 0
MULTIPLIER_COLUMN = 3

MULTIPLIER_SW = "0"
MULTIPLIER_HW_16 = ("1", "2")
MULTIPLIER_HW_32 = ("4", "8")

PREFIX = """//===--- MSP430Target.def - MSP430 Feature/Processor Database----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the MSP430 devices and their features.
//
// Generated from TI's devices.csv in version {} using the script in
// Target/MSP430/gen-msp430-def.py - use this tool rather than adding
// new MCUs by hand.
//
//===----------------------------------------------------------------------===//

#ifndef MSP430_MCU_FEAT
#define MSP430_MCU_FEAT(NAME, HWMULT) MSP430_MCU(NAME)
#endif

#ifndef MSP430_MCU
#define MSP430_MCU(NAME)
#endif

"""

SUFFIX = """
// Generic MCUs
MSP430_MCU("msp430i2xxgeneric")

#undef MSP430_MCU
#undef MSP430_MCU_FEAT
"""


def csv2def(csv_path, def_path):
"""
Parse the devices.csv file at the given path, generate the definitions and
write them to the given path.

:param csv_path: Path to the devices.csv to parse
:type csv_path: str
:param def_path: Path to the output file to write the definitions to
"type def_path: str
"""

mcus_multiplier_sw = []
mcus_multiplier_hw_16 = []
mcus_multiplier_hw_32 = []
version = "unknown"

with open(csv_path) as csv_file:
csv_reader = csv.reader(csv_file)
while True:
row = next(csv_reader)
if len(row) < MULTIPLIER_COLUMN:
continue

if row[DEVICE_COLUMN] == "# Device Name":
assert row[MULTIPLIER_COLUMN] == "MPY_TYPE", "File format changed"
break

if row[0] == "Version:":
version = row[1]

for row in csv_reader:
if row[DEVICE_COLUMN].endswith("generic"):
continue
if row[MULTIPLIER_COLUMN] == MULTIPLIER_SW:
mcus_multiplier_sw.append(row[DEVICE_COLUMN])
elif row[MULTIPLIER_COLUMN] in MULTIPLIER_HW_16:
mcus_multiplier_hw_16.append(row[DEVICE_COLUMN])
elif row[MULTIPLIER_COLUMN] in MULTIPLIER_HW_32:
mcus_multiplier_hw_32.append(row[DEVICE_COLUMN])
else:
assert 0, "Unknown multiplier type"

with open(def_path, "w") as def_file:
def_file.write(PREFIX.format(version))

for mcu in mcus_multiplier_sw:
def_file.write(f'MSP430_MCU("{mcu}")\n')

def_file.write("\n// With 16-bit hardware multiplier\n")

for mcu in mcus_multiplier_hw_16:
def_file.write(f'MSP430_MCU_FEAT("{mcu}", "16bit")\n')

def_file.write("\n// With 32-bit hardware multiplier\n")

for mcu in mcus_multiplier_hw_32:
def_file.write(f'MSP430_MCU_FEAT("{mcu}", "32bit")\n')

def_file.write(SUFFIX)


if __name__ == "__main__":
if len(sys.argv) != 3:
sys.exit(f"Usage: {sys.argv[0]} <CSV_FILE> <DEF_FILE>")

csv2def(sys.argv[1], sys.argv[2])
20 changes: 20 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ struct TransferrableTargetInfo {
unsigned char LongLongWidth, LongLongAlign;
unsigned char Int128Align;

// This is an optional parameter for targets that
// don't use 'LongLongAlign' for '_BitInt' max alignment
std::optional<unsigned> BitIntMaxAlign;

// Fixed point bit widths
unsigned char ShortAccumWidth, ShortAccumAlign;
unsigned char AccumWidth, AccumAlign;
Expand Down Expand Up @@ -518,6 +522,22 @@ class TargetInfo : public TransferrableTargetInfo,
/// getInt128Align() - Returns the alignment of Int128.
unsigned getInt128Align() const { return Int128Align; }

/// getBitIntMaxAlign() - Returns the maximum possible alignment of
/// '_BitInt' and 'unsigned _BitInt'.
unsigned getBitIntMaxAlign() const {
return BitIntMaxAlign.value_or(LongLongAlign);
}

/// getBitIntAlign/Width - Return aligned size of '_BitInt' and
/// 'unsigned _BitInt' for this target, in bits.
unsigned getBitIntWidth(unsigned NumBits) const {
return llvm::alignTo(NumBits, getBitIntAlign(NumBits));
}
unsigned getBitIntAlign(unsigned NumBits) const {
return std::clamp<unsigned>(llvm::PowerOf2Ceil(NumBits), getCharWidth(),
getBitIntMaxAlign());
}

/// getShortAccumWidth/Align - Return the size of 'signed short _Accum' and
/// 'unsigned short _Accum' for this target, in bits.
unsigned getShortAccumWidth() const { return ShortAccumWidth; }
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ TYPE_TRAIT_1(__is_referenceable, IsReferenceable, KEYCXX)
TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX)
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX)
TYPE_TRAIT_2(__reference_converts_from_temporary, ReferenceConvertsFromTemporary, KEYCXX)

// Embarcadero Expression Traits
EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX)
Expand Down
58 changes: 58 additions & 0 deletions clang/include/clang/Basic/arm_sme.td
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,40 @@ let TargetGuard = "sme2,sme-f64f64" in {
def SVMLS_LANE_VG1x4_F64 : Inst<"svmls_lane_za64[_{d}]_vg1x4", "vm4di", "d", MergeNone, "aarch64_sme_fmls_lane_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_1>]>;
}

let TargetGuard = "sme-f16f16" in {
def SVMLA_MULTI_VG1x2_F16 : Inst<"svmla_za16[_f16]_vg1x2", "vm22", "h", MergeNone, "aarch64_sme_fmla_vg1x2", [IsStreaming, IsInOutZA], []>;
def SVMLA_MULTI_VG1x4_F16 : Inst<"svmla_za16[_f16]_vg1x4", "vm44", "h", MergeNone, "aarch64_sme_fmla_vg1x4", [IsStreaming, IsInOutZA], []>;
def SVMLS_MULTI_VG1x2_F16 : Inst<"svmls_za16[_f16]_vg1x2", "vm22", "h", MergeNone, "aarch64_sme_fmls_vg1x2", [IsStreaming, IsInOutZA], []>;
def SVMLS_MULTI_VG1x4_F16 : Inst<"svmls_za16[_f16]_vg1x4", "vm44", "h", MergeNone, "aarch64_sme_fmls_vg1x4", [IsStreaming, IsInOutZA], []>;

def SVMLA_SINGLE_VG1x2_F16 : Inst<"svmla[_single]_za16[_f16]_vg1x2", "vm2d", "h", MergeNone, "aarch64_sme_fmla_single_vg1x2", [IsStreaming, IsInOutZA], []>;
def SVMLA_SINGLE_VG1x4_F16 : Inst<"svmla[_single]_za16[_f16]_vg1x4", "vm4d", "h", MergeNone, "aarch64_sme_fmla_single_vg1x4", [IsStreaming, IsInOutZA], []>;
def SVMLS_SINGLE_VG1x2_F16 : Inst<"svmls[_single]_za16[_f16]_vg1x2", "vm2d", "h", MergeNone, "aarch64_sme_fmls_single_vg1x2", [IsStreaming, IsInOutZA], []>;
def SVMLS_SINGLE_VG1x4_F16 : Inst<"svmls[_single]_za16[_f16]_vg1x4", "vm4d", "h", MergeNone, "aarch64_sme_fmls_single_vg1x4", [IsStreaming, IsInOutZA], []>;

def SVMLA_LANE_VG1x2_F16 : Inst<"svmla_lane_za16[_f16]_vg1x2", "vm2di", "h", MergeNone, "aarch64_sme_fmla_lane_vg1x2", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLA_LANE_VG1x4_F16 : Inst<"svmla_lane_za16[_f16]_vg1x4", "vm4di", "h", MergeNone, "aarch64_sme_fmla_lane_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLS_LANE_VG1x2_F16 : Inst<"svmls_lane_za16[_f16]_vg1x2", "vm2di", "h", MergeNone, "aarch64_sme_fmls_lane_vg1x2", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLS_LANE_VG1x4_F16 : Inst<"svmls_lane_za16[_f16]_vg1x4", "vm4di", "h", MergeNone, "aarch64_sme_fmls_lane_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>;
}

let TargetGuard = "sme2,b16b16" in {
def SVMLA_MULTI_VG1x2_BF16 : Inst<"svmla_za16[_bf16]_vg1x2", "vm22", "b", MergeNone, "aarch64_sme_fmla_vg1x2", [IsStreaming, IsInOutZA], []>;
def SVMLA_MULTI_VG1x4_BF16 : Inst<"svmla_za16[_bf16]_vg1x4", "vm44", "b", MergeNone, "aarch64_sme_fmla_vg1x4", [IsStreaming, IsInOutZA], []>;
def SVMLS_MULTI_VG1x2_BF16 : Inst<"svmls_za16[_bf16]_vg1x2", "vm22", "b", MergeNone, "aarch64_sme_fmls_vg1x2", [IsStreaming, IsInOutZA], []>;
def SVMLS_MULTI_VG1x4_BF16 : Inst<"svmls_za16[_bf16]_vg1x4", "vm44", "b", MergeNone, "aarch64_sme_fmls_vg1x4", [IsStreaming, IsInOutZA], []>;

def SVMLA_SINGLE_VG1x2_BF16 : Inst<"svmla[_single]_za16[_bf16]_vg1x2", "vm2d", "b", MergeNone, "aarch64_sme_fmla_single_vg1x2", [IsStreaming, IsInOutZA], []>;
def SVMLA_SINGLE_VG1x4_BF16 : Inst<"svmla[_single]_za16[_bf16]_vg1x4", "vm4d", "b", MergeNone, "aarch64_sme_fmla_single_vg1x4", [IsStreaming, IsInOutZA], []>;
def SVMLS_SINGLE_VG1x2_BF16 : Inst<"svmls[_single]_za16[_bf16]_vg1x2", "vm2d", "b", MergeNone, "aarch64_sme_fmls_single_vg1x2", [IsStreaming, IsInOutZA], []>;
def SVMLS_SINGLE_VG1x4_BF16 : Inst<"svmls[_single]_za16[_bf16]_vg1x4", "vm4d", "b", MergeNone, "aarch64_sme_fmls_single_vg1x4", [IsStreaming, IsInOutZA], []>;

def SVMLA_LANE_VG1x2_BF16 : Inst<"svmla_lane_za16[_bf16]_vg1x2", "vm2di", "b", MergeNone, "aarch64_sme_fmla_lane_vg1x2", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLA_LANE_VG1x4_BF16 : Inst<"svmla_lane_za16[_bf16]_vg1x4", "vm4di", "b", MergeNone, "aarch64_sme_fmla_lane_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLS_LANE_VG1x2_BF16 : Inst<"svmls_lane_za16[_bf16]_vg1x2", "vm2di", "b", MergeNone, "aarch64_sme_fmls_lane_vg1x2", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLS_LANE_VG1x4_BF16 : Inst<"svmls_lane_za16[_bf16]_vg1x4", "vm4di", "b", MergeNone, "aarch64_sme_fmls_lane_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>;
}

// FMLAL/FMLSL/UMLAL/SMLAL
// SMLALL/UMLALL/USMLALL/SUMLALL
let TargetGuard = "sme2" in {
Expand Down Expand Up @@ -674,3 +708,27 @@ let TargetGuard = "sme2" in {
def SVLUTI2_LANE_ZT_X2 : Inst<"svluti2_lane_zt_{d}_x2", "2.di[i", "cUcsUsiUibhf", MergeNone, "aarch64_sme_luti2_lane_zt_x2", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_7>]>;
def SVLUTI4_LANE_ZT_X2 : Inst<"svluti4_lane_zt_{d}_x2", "2.di[i", "cUcsUsiUibhf", MergeNone, "aarch64_sme_luti4_lane_zt_x2", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_3>]>;
}

////////////////////////////////////////////////////////////////////////////////
// SME2p1 - FMOPA, FMOPS (non-widening)
let TargetGuard = "sme2,b16b16" in {
def SVMOPA_BF16_NW : SInst<"svmopa_za16[_bf16]_m", "viPPdd", "b",
MergeNone, "aarch64_sme_mopa",
[IsStreaming, IsInOutZA],
[ImmCheck<0, ImmCheck0_1>]>;
def SVMOPS_BF16_NW : SInst<"svmops_za16[_bf16]_m", "viPPdd", "b",
MergeNone, "aarch64_sme_mops",
[IsStreaming, IsInOutZA],
[ImmCheck<0, ImmCheck0_1>]>;
}

let TargetGuard = "sme-f16f16" in {
def SVMOPA_F16_NW : SInst<"svmopa_za16[_f16]_m", "viPPdd", "h",
MergeNone, "aarch64_sme_mopa",
[IsStreaming, IsInOutZA],
[ImmCheck<0, ImmCheck0_1>]>;
def SVMOPS_F16_NW : SInst<"svmops_za16[_f16]_m", "viPPdd", "h",
MergeNone, "aarch64_sme_mops",
[IsStreaming, IsInOutZA],
[ImmCheck<0, ImmCheck0_1>]>;
}
Loading