290 changes: 287 additions & 3 deletions bolt/lib/Passes/LongJmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,26 @@
//===----------------------------------------------------------------------===//

#include "bolt/Passes/LongJmp.h"
#include "bolt/Core/ParallelUtilities.h"
#include "llvm/Support/MathExtras.h"

#define DEBUG_TYPE "longjmp"

using namespace llvm;

namespace opts {
extern cl::OptionCategory BoltCategory;
extern cl::OptionCategory BoltOptCategory;
extern llvm::cl::opt<unsigned> AlignText;
extern cl::opt<unsigned> AlignFunctions;
extern cl::opt<bool> UseOldText;
extern cl::opt<bool> HotFunctionsAtEnd;

static cl::opt<bool>
CompactCodeModel("compact-code-model",
cl::desc("generate code for binaries <128MB on AArch64"),
cl::init(false), cl::cat(BoltCategory));

static cl::opt<bool> GroupStubs("group-stubs",
cl::desc("share stubs across functions"),
cl::init(true), cl::cat(BoltOptCategory));
Expand Down Expand Up @@ -61,10 +69,10 @@ static BinaryBasicBlock *getBBAtHotColdSplitPoint(BinaryFunction &Func) {
if (Next != E && (*Next)->isCold())
return *I;
}
llvm_unreachable("No hot-colt split point found");
llvm_unreachable("No hot-cold split point found");
}

static bool shouldInsertStub(const BinaryContext &BC, const MCInst &Inst) {
static bool mayNeedStub(const BinaryContext &BC, const MCInst &Inst) {
return (BC.MIB->isBranch(Inst) || BC.MIB->isCall(Inst)) &&
!BC.MIB->isIndirectBranch(Inst) && !BC.MIB->isIndirectCall(Inst);
}
Expand Down Expand Up @@ -570,7 +578,7 @@ Error LongJmpPass::relax(BinaryFunction &Func, bool &Modified) {
if (BC.MIB->isPseudo(Inst))
continue;

if (!shouldInsertStub(BC, Inst)) {
if (!mayNeedStub(BC, Inst)) {
DotAddress += InsnSize;
continue;
}
Expand Down Expand Up @@ -634,7 +642,283 @@ Error LongJmpPass::relax(BinaryFunction &Func, bool &Modified) {
return Error::success();
}

void LongJmpPass::relaxLocalBranches(BinaryFunction &BF) {
BinaryContext &BC = BF.getBinaryContext();
auto &MIB = BC.MIB;

// Quick path.
if (!BF.isSplit() && BF.estimateSize() < ShortestJumpSpan)
return;

auto isBranchOffsetInRange = [&](const MCInst &Inst, int64_t Offset) {
const unsigned Bits = MIB->getPCRelEncodingSize(Inst);
return isIntN(Bits, Offset);
};

auto isBlockInRange = [&](const MCInst &Inst, uint64_t InstAddress,
const BinaryBasicBlock &BB) {
const int64_t Offset = BB.getOutputStartAddress() - InstAddress;
return isBranchOffsetInRange(Inst, Offset);
};

// Keep track of *all* function trampolines that are going to be added to the
// function layout at the end of relaxation.
std::vector<std::pair<BinaryBasicBlock *, std::unique_ptr<BinaryBasicBlock>>>
FunctionTrampolines;

// Function fragments are relaxed independently.
for (FunctionFragment &FF : BF.getLayout().fragments()) {
// Fill out code size estimation for the fragment. Use output BB address
// ranges to store offsets from the start of the function fragment.
uint64_t CodeSize = 0;
for (BinaryBasicBlock *BB : FF) {
BB->setOutputStartAddress(CodeSize);
CodeSize += BB->estimateSize();
BB->setOutputEndAddress(CodeSize);
}

// Dynamically-updated size of the fragment.
uint64_t FragmentSize = CodeSize;

// Size of the trampoline in bytes.
constexpr uint64_t TrampolineSize = 4;

// Trampolines created for the fragment. DestinationBB -> TrampolineBB.
// NB: here we store only the first trampoline created for DestinationBB.
DenseMap<const BinaryBasicBlock *, BinaryBasicBlock *> FragmentTrampolines;

// Create a trampoline code after \p BB or at the end of the fragment if BB
// is nullptr. If \p UpdateOffsets is true, update FragmentSize and offsets
// for basic blocks affected by the insertion of the trampoline.
auto addTrampolineAfter = [&](BinaryBasicBlock *BB,
BinaryBasicBlock *TargetBB, uint64_t Count,
bool UpdateOffsets = true) {
FunctionTrampolines.emplace_back(BB ? BB : FF.back(),
BF.createBasicBlock());
BinaryBasicBlock *TrampolineBB = FunctionTrampolines.back().second.get();

MCInst Inst;
{
auto L = BC.scopeLock();
MIB->createUncondBranch(Inst, TargetBB->getLabel(), BC.Ctx.get());
}
TrampolineBB->addInstruction(Inst);
TrampolineBB->addSuccessor(TargetBB, Count);
TrampolineBB->setExecutionCount(Count);
const uint64_t TrampolineAddress =
BB ? BB->getOutputEndAddress() : FragmentSize;
TrampolineBB->setOutputStartAddress(TrampolineAddress);
TrampolineBB->setOutputEndAddress(TrampolineAddress + TrampolineSize);
TrampolineBB->setFragmentNum(FF.getFragmentNum());

if (!FragmentTrampolines.lookup(TargetBB))
FragmentTrampolines[TargetBB] = TrampolineBB;

if (!UpdateOffsets)
return TrampolineBB;

FragmentSize += TrampolineSize;

// If the trampoline was added at the end of the fragment, offsets of
// other fragments should stay intact.
if (!BB)
return TrampolineBB;

// Update offsets for blocks after BB.
for (BinaryBasicBlock *IBB : FF) {
if (IBB->getOutputStartAddress() >= TrampolineAddress) {
IBB->setOutputStartAddress(IBB->getOutputStartAddress() +
TrampolineSize);
IBB->setOutputEndAddress(IBB->getOutputEndAddress() + TrampolineSize);
}
}

// Update offsets for trampolines in this fragment that are placed after
// the new trampoline. Note that trampoline blocks are not part of the
// function/fragment layout until we add them right before the return
// from relaxLocalBranches().
for (auto &Pair : FunctionTrampolines) {
BinaryBasicBlock *IBB = Pair.second.get();
if (IBB->getFragmentNum() != TrampolineBB->getFragmentNum())
continue;
if (IBB == TrampolineBB)
continue;
if (IBB->getOutputStartAddress() >= TrampolineAddress) {
IBB->setOutputStartAddress(IBB->getOutputStartAddress() +
TrampolineSize);
IBB->setOutputEndAddress(IBB->getOutputEndAddress() + TrampolineSize);
}
}

return TrampolineBB;
};

// Pre-populate trampolines by splitting unconditional branches from the
// containing basic block.
for (BinaryBasicBlock *BB : FF) {
MCInst *Inst = BB->getLastNonPseudoInstr();
if (!Inst || !MIB->isUnconditionalBranch(*Inst))
continue;

const MCSymbol *TargetSymbol = MIB->getTargetSymbol(*Inst);
BB->eraseInstruction(BB->findInstruction(Inst));
BB->setOutputEndAddress(BB->getOutputEndAddress() - TrampolineSize);

BinaryBasicBlock::BinaryBranchInfo BI;
BinaryBasicBlock *TargetBB = BB->getSuccessor(TargetSymbol, BI);

BinaryBasicBlock *TrampolineBB =
addTrampolineAfter(BB, TargetBB, BI.Count, /*UpdateOffsets*/ false);
BB->replaceSuccessor(TargetBB, TrampolineBB, BI.Count);
}

/// Relax the branch \p Inst in basic block \p BB that targets \p TargetBB.
/// \p InstAddress contains offset of the branch from the start of the
/// containing function fragment.
auto relaxBranch = [&](BinaryBasicBlock *BB, MCInst &Inst,
uint64_t InstAddress, BinaryBasicBlock *TargetBB) {
BinaryFunction *BF = BB->getParent();

// Use branch taken count for optimal relaxation.
const uint64_t Count = BB->getBranchInfo(*TargetBB).Count;
assert(Count != BinaryBasicBlock::COUNT_NO_PROFILE &&
"Expected valid branch execution count");

// Try to reuse an existing trampoline without introducing any new code.
BinaryBasicBlock *TrampolineBB = FragmentTrampolines.lookup(TargetBB);
if (TrampolineBB && isBlockInRange(Inst, InstAddress, *TrampolineBB)) {
BB->replaceSuccessor(TargetBB, TrampolineBB, Count);
TrampolineBB->setExecutionCount(TrampolineBB->getExecutionCount() +
Count);
auto L = BC.scopeLock();
MIB->replaceBranchTarget(Inst, TrampolineBB->getLabel(), BC.Ctx.get());
return;
}

// For cold branches, check if we can introduce a trampoline at the end
// of the fragment that is within the branch reach. Note that such
// trampoline may change address later and become unreachable in which
// case we will need further relaxation.
const int64_t OffsetToEnd = FragmentSize - InstAddress;
if (Count == 0 && isBranchOffsetInRange(Inst, OffsetToEnd)) {
TrampolineBB = addTrampolineAfter(nullptr, TargetBB, Count);
BB->replaceSuccessor(TargetBB, TrampolineBB, Count);
auto L = BC.scopeLock();
MIB->replaceBranchTarget(Inst, TrampolineBB->getLabel(), BC.Ctx.get());

return;
}

// Insert a new block after the current one and use it as a trampoline.
TrampolineBB = addTrampolineAfter(BB, TargetBB, Count);

// If the other successor is a fall-through, invert the condition code.
const BinaryBasicBlock *const NextBB =
BF->getLayout().getBasicBlockAfter(BB, /*IgnoreSplits*/ false);
if (BB->getConditionalSuccessor(false) == NextBB) {
BB->swapConditionalSuccessors();
auto L = BC.scopeLock();
MIB->reverseBranchCondition(Inst, NextBB->getLabel(), BC.Ctx.get());
} else {
auto L = BC.scopeLock();
MIB->replaceBranchTarget(Inst, TrampolineBB->getLabel(), BC.Ctx.get());
}
BB->replaceSuccessor(TargetBB, TrampolineBB, Count);
};

bool MayNeedRelaxation;
uint64_t NumIterations = 0;
do {
MayNeedRelaxation = false;
++NumIterations;
for (auto BBI = FF.begin(); BBI != FF.end(); ++BBI) {
BinaryBasicBlock *BB = *BBI;
uint64_t NextInstOffset = BB->getOutputStartAddress();
for (MCInst &Inst : *BB) {
const size_t InstAddress = NextInstOffset;
if (!MIB->isPseudo(Inst))
NextInstOffset += 4;

if (!mayNeedStub(BF.getBinaryContext(), Inst))
continue;

const size_t BitsAvailable = MIB->getPCRelEncodingSize(Inst);

// Span of +/-128MB.
if (BitsAvailable == LongestJumpBits)
continue;

const MCSymbol *TargetSymbol = MIB->getTargetSymbol(Inst);
BinaryBasicBlock *TargetBB = BB->getSuccessor(TargetSymbol);
assert(TargetBB &&
"Basic block target expected for conditional branch.");

// Check if the relaxation is needed.
if (TargetBB->getFragmentNum() == FF.getFragmentNum() &&
isBlockInRange(Inst, InstAddress, *TargetBB))
continue;

relaxBranch(BB, Inst, InstAddress, TargetBB);

MayNeedRelaxation = true;
}
}

// We may have added new instructions, but the whole fragment is less than
// the minimum branch span.
if (FragmentSize < ShortestJumpSpan)
MayNeedRelaxation = false;

} while (MayNeedRelaxation);

LLVM_DEBUG({
if (NumIterations > 2) {
dbgs() << "BOLT-DEBUG: relaxed fragment " << FF.getFragmentNum().get()
<< " of " << BF << " in " << NumIterations << " iterations\n";
}
});
(void)NumIterations;
}

// Add trampoline blocks from all fragments to the layout.
DenseMap<BinaryBasicBlock *, std::vector<std::unique_ptr<BinaryBasicBlock>>>
Insertions;
for (std::pair<BinaryBasicBlock *, std::unique_ptr<BinaryBasicBlock>> &Pair :
FunctionTrampolines) {
if (!Pair.second)
continue;
Insertions[Pair.first].emplace_back(std::move(Pair.second));
}

for (auto &Pair : Insertions) {
BF.insertBasicBlocks(Pair.first, std::move(Pair.second),
/*UpdateLayout*/ true, /*UpdateCFI*/ true,
/*RecomputeLPs*/ false);
}
}

Error LongJmpPass::runOnFunctions(BinaryContext &BC) {

if (opts::CompactCodeModel) {
BC.outs()
<< "BOLT-INFO: relaxing branches for compact code model (<128MB)\n";

ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
relaxLocalBranches(BF);
};

ParallelUtilities::PredicateTy SkipPredicate =
[&](const BinaryFunction &BF) {
return !BC.shouldEmit(BF) || !BF.isSimple();
};

ParallelUtilities::runOnEachFunction(
BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun,
SkipPredicate, "RelaxLocalBranches");

return Error::success();
}

BC.outs() << "BOLT-INFO: Starting stub-insertion pass\n";
std::vector<BinaryFunction *> Sorted = BC.getSortedFunctions();
bool Modified;
Expand Down
111 changes: 77 additions & 34 deletions bolt/lib/Profile/DataAggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -778,42 +778,75 @@ 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));
}
uint64_t Mispreds, bool IsPreagg) {
// Returns whether \p Offset in \p Func contains a return instruction.
auto checkReturn = [&](const BinaryFunction &Func, const uint64_t Offset) {
auto isReturn = [&](auto MI) { return MI && BC->MIB->isReturn(*MI); };
return Func.hasInstructions()
? isReturn(Func.getInstructionAtOffset(Offset))
: isReturn(Func.disassembleInstructionAtOffset(Offset));
};

if (BAT)
Addr = BAT->translate(Func->getAddress(), Addr, IsFrom);
// Returns whether \p Offset in \p Func may be a call continuation excluding
// entry points and landing pads.
auto checkCallCont = [&](const BinaryFunction &Func, const uint64_t Offset) {
// No call continuation at a function start.
if (!Offset)
return false;

// FIXME: support BAT case where the function might be in empty state
// (split fragments declared non-simple).
if (!Func.hasCFG())
return false;

// The offset should not be an entry point or a landing pad.
const BinaryBasicBlock *ContBB = Func.getBasicBlockAtOffset(Offset);
return ContBB && !ContBB->isEntryPoint() && !ContBB->isLandingPad();
};

if (BinaryFunction *ParentFunc = getBATParentFunction(*Func)) {
Func = ParentFunc;
if (IsFrom)
NumColdSamples += Count;
}
// Mutates \p Addr to an offset into the containing function, performing BAT
// offset translation and parent lookup.
//
// Returns the containing function (or BAT parent) and whether the address
// corresponds to a return (if \p IsFrom) or a call continuation (otherwise).
auto handleAddress = [&](uint64_t &Addr, bool IsFrom) {
BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr);
if (!Func)
return std::pair{Func, false};

return Func;
}
return nullptr;
Addr -= Func->getAddress();

bool IsRetOrCallCont =
IsFrom ? checkReturn(*Func, Addr) : checkCallCont(*Func, Addr);

if (BAT)
Addr = BAT->translate(Func->getAddress(), Addr, IsFrom);

BinaryFunction *ParentFunc = getBATParentFunction(*Func);
if (!ParentFunc)
return std::pair{Func, IsRetOrCallCont};

if (IsFrom)
NumColdSamples += Count;

return std::pair{ParentFunc, IsRetOrCallCont};
};

BinaryFunction *FromFunc = handleAddress(From, /*IsFrom=*/true);
uint64_t ToOrig = To;
auto [FromFunc, IsReturn] = handleAddress(From, /*IsFrom*/ true);
auto [ToFunc, IsCallCont] = handleAddress(To, /*IsFrom*/ false);
if (!FromFunc && !ToFunc)
return false;

// Record call to continuation trace.
if (IsPreagg && FromFunc != ToFunc && (IsReturn || IsCallCont)) {
LBREntry First{ToOrig - 1, ToOrig - 1, false};
LBREntry Second{ToOrig, ToOrig, false};
return doTrace(First, Second, Count);
}
// Ignore returns.
if (IsReturn)
return true;
BinaryFunction *ToFunc = handleAddress(To, /*IsFrom=*/false);
if (!FromFunc && !ToFunc)
return false;

// Treat recursive control transfers as inter-branches.
if (FromFunc == ToFunc && To != 0) {
Expand All @@ -830,10 +863,19 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second,
BinaryFunction *ToFunc = getBinaryFunctionContainingAddress(Second.From);
if (!FromFunc || !ToFunc) {
LLVM_DEBUG({
dbgs() << "Out of range trace starting in " << FromFunc->getPrintName()
<< formatv(" @ {0:x}", First.To - FromFunc->getAddress())
<< " and ending in " << ToFunc->getPrintName()
<< formatv(" @ {0:x}\n", Second.From - ToFunc->getAddress());
dbgs() << "Out of range trace starting in ";
if (FromFunc)
dbgs() << formatv("{0} @ {1:x}", *FromFunc,
First.To - FromFunc->getAddress());
else
dbgs() << Twine::utohexstr(First.To);
dbgs() << " and ending in ";
if (ToFunc)
dbgs() << formatv("{0} @ {1:x}", *ToFunc,
Second.From - ToFunc->getAddress());
else
dbgs() << Twine::utohexstr(Second.From);
dbgs() << '\n';
});
NumLongRangeTraces += Count;
return false;
Expand Down Expand Up @@ -1620,7 +1662,8 @@ void DataAggregator::processBranchEvents() {
for (const auto &AggrLBR : BranchLBRs) {
const Trace &Loc = AggrLBR.first;
const TakenBranchInfo &Info = AggrLBR.second;
doBranch(Loc.From, Loc.To, Info.TakenCount, Info.MispredCount);
doBranch(Loc.From, Loc.To, Info.TakenCount, Info.MispredCount,
/*IsPreagg*/ false);
}
}

Expand Down Expand Up @@ -1781,7 +1824,7 @@ void DataAggregator::processPreAggregated() {
switch (AggrEntry.EntryType) {
case AggregatedLBREntry::BRANCH:
doBranch(AggrEntry.From.Offset, AggrEntry.To.Offset, AggrEntry.Count,
AggrEntry.Mispreds);
AggrEntry.Mispreds, /*IsPreagg*/ true);
break;
case AggregatedLBREntry::FT:
case AggregatedLBREntry::FT_EXTERNAL_ORIGIN: {
Expand Down
13 changes: 3 additions & 10 deletions bolt/lib/Profile/YAMLProfileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,7 @@ bool YAMLProfileReader::parseFunctionProfile(
BB.setExecutionCount(YamlBB.ExecCount);

for (const yaml::bolt::CallSiteInfo &YamlCSI : YamlBB.CallSites) {
BinaryFunction *Callee = YamlCSI.DestId < YamlProfileToFunction.size()
? YamlProfileToFunction[YamlCSI.DestId]
: nullptr;
BinaryFunction *Callee = YamlProfileToFunction.lookup(YamlCSI.DestId);
bool IsFunction = Callee ? true : false;
MCSymbol *CalleeSymbol = nullptr;
if (IsFunction)
Expand Down Expand Up @@ -703,7 +701,7 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
break;
}
}
YamlProfileToFunction.resize(YamlBP.Functions.size() + 1);
YamlProfileToFunction.reserve(YamlBP.Functions.size());

// Computes hash for binary functions.
if (opts::MatchProfileWithFunctionHash) {
Expand Down Expand Up @@ -756,12 +754,7 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
NormalizeByCalls = usesEvent("branches");
uint64_t NumUnused = 0;
for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) {
if (YamlBF.Id >= YamlProfileToFunction.size()) {
// Such profile was ignored.
++NumUnused;
continue;
}
if (BinaryFunction *BF = YamlProfileToFunction[YamlBF.Id])
if (BinaryFunction *BF = YamlProfileToFunction.lookup(YamlBF.Id))
parseFunctionProfile(*BF, YamlBF);
else
++NumUnused;
Expand Down
4 changes: 2 additions & 2 deletions bolt/lib/Rewrite/PseudoProbeRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ void PseudoProbeRewriter::parsePseudoProbe(bool ProfiledOnly) {

StringRef Contents = PseudoProbeDescSection->getContents();
if (!ProbeDecoder.buildGUID2FuncDescMap(
reinterpret_cast<const uint8_t *>(Contents.data()),
Contents.size())) {
reinterpret_cast<const uint8_t *>(Contents.data()), Contents.size(),
/*IsMMapped*/ true)) {
errs() << "BOLT-WARNING: fail in building GUID2FuncDescMap\n";
return;
}
Expand Down
39 changes: 37 additions & 2 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,9 +789,44 @@ void RewriteInstance::discoverFileObjects() {
BinarySection Section(*BC, *cantFail(Sym.getSection()));
return Section.isAllocatable();
};
auto checkSymbolInSection = [this](const SymbolInfo &S) {
// Sometimes, we encounter symbols with addresses outside their section. If
// such symbols happen to fall into another section, they can interfere with
// disassembly. Notably, this occurs with AArch64 marker symbols ($d and $t)
// that belong to .eh_frame, but end up pointing into .text.
// As a workaround, we ignore all symbols that lie outside their sections.
auto Section = cantFail(S.Symbol.getSection());

// Accept all absolute symbols.
if (Section == InputFile->section_end())
return true;

uint64_t SecStart = Section->getAddress();
uint64_t SecEnd = SecStart + Section->getSize();
uint64_t SymEnd = S.Address + ELFSymbolRef(S.Symbol).getSize();
if (S.Address >= SecStart && SymEnd <= SecEnd)
return true;

auto SymType = cantFail(S.Symbol.getType());
// Skip warnings for common benign cases.
if (opts::Verbosity < 1 && SymType == SymbolRef::ST_Other)
return false; // E.g. ELF::STT_TLS.

auto SymName = S.Symbol.getName();
auto SecName = cantFail(S.Symbol.getSection())->getName();
BC->errs() << "BOLT-WARNING: ignoring symbol "
<< (SymName ? *SymName : "[unnamed]") << " at 0x"
<< Twine::utohexstr(S.Address) << ", which lies outside "
<< (SecName ? *SecName : "[unnamed]") << "\n";

return false;
};
for (const SymbolRef &Symbol : InputFile->symbols())
if (isSymbolInMemory(Symbol))
SortedSymbols.push_back({cantFail(Symbol.getAddress()), Symbol});
if (isSymbolInMemory(Symbol)) {
SymbolInfo SymInfo{cantFail(Symbol.getAddress()), Symbol};
if (checkSymbolInSection(SymInfo))
SortedSymbols.push_back(SymInfo);
}

auto CompareSymbols = [this](const SymbolInfo &A, const SymbolInfo &B) {
if (A.Address != B.Address)
Expand Down
56 changes: 56 additions & 0 deletions bolt/test/AArch64/Inputs/spurious-marker-symbol.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_AARCH64
Entry: 0x2a0000
ProgramHeaders:
- Type: PT_PHDR
Flags: [ PF_R ]
VAddr: 0x40
Align: 0x8
FileSize: 0xa8
MemSize: 0xa8
Offset: 0x40
- Type: PT_LOAD
Flags: [ PF_R ]
VAddr: 0x0
Align: 0x10000
FileSize: 0xf8
MemSize: 0xf8
Offset: 0x0
- Type: PT_LOAD
Flags: [ PF_X, PF_R ]
VAddr: 0x2a0000
Align: 0x10000
FirstSec: .text
LastSec: .ignored
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x2a0000
AddressAlign: 0x4
Content: 400580d2c0035fd6
- Name: .ignored
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Address: 0x2a0008
AddressAlign: 0x8
Size: 0x8
- Name: .eh_frame
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Address: 0x2a0010
AddressAlign: 0x8
Content: 1000000000000000017a520004781e010b0c1f00140000001800000000002a0008000000000e01410e010000
Symbols:
- Name: func
Section: .text
Value: 0x2a0000
Size: 0x8
- Name: '$d.42'
Section: .ignored
Value: 0x2a0004
...
92 changes: 92 additions & 0 deletions bolt/test/AArch64/compact-code-model.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
## Check that llvm-bolt successfully relaxes branches for compact (<128MB) code
## model.

# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
# RUN: link_fdata %s %t.o %t.fdata
# RUN: llvm-strip --strip-unneeded %t.o
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -static
# RUN: llvm-bolt %t.exe -o %t.bolt --data %t.fdata --split-functions \
# RUN: --keep-nops --compact-code-model
# RUN: llvm-objdump -d \
# RUN: --disassemble-symbols=_start,_start.cold.0,foo,foo.cold.0 %t.bolt \
# RUN: | FileCheck %s
# RUN: llvm-nm -nS %t.bolt | FileCheck %s --check-prefix=CHECK-NM

## Fragments of _start and foo will be separated by large_function which is over
## 1MB in size - larger than all conditional branches can cover requiring branch
## relaxation.

# CHECK-NM: _start
# CHECK-NM: foo
# CHECK-NM: 0000000000124f84 T large_function
# CHECK-NM: _start.cold.0
# CHECK-NM: foo.cold.0

.text
.globl _start
.type _start, %function
_start:
# CHECK: <_start>:
# FDATA: 0 [unknown] 0 1 _start 0 0 100
.cfi_startproc
cmp x0, 1
b.eq .L0
# CHECK: b.eq
# CHECK-NEXT: b
# CHECK-NEXT: b

bl large_function
.L0:
ret x30
.cfi_endproc
.size _start, .-_start

## Check that long branch in foo() is reused during relaxation. I.e. we should
## see just one branch to the cold fragment.

.globl foo
.type foo, %function
foo:
# CHECK: <foo>:
# FDATA: 0 [unknown] 0 1 foo 0 0 100
.cfi_startproc
cmp x0, 0
.T0:
b.eq .ERROR
# CHECK: b {{.*}} <foo.cold.0>
# CHECK-NOT: b {{.*}} <foo.cold.0>
# FDATA: 1 foo #.T0# 1 foo #.T1# 0 100
.T1:
bl large_function
cmp x0, 1
.T2:
b.eq .ERROR
# FDATA: 1 foo #.T2# 1 foo #.T3# 0 100
.T3:
mov x1, x0
mov x0, 0
ret x30

# CHECK: <foo.cold.0>:
# CHECK-NEXT: mov x0, #0x1
# CHECK-NEXT: ret
.ERROR:
mov x0, 1
ret x30
.cfi_endproc
.size foo, .-foo

.globl large_function
.type large_function, %function
large_function:
# FDATA: 0 [unknown] 0 1 large_function 0 0 100
.cfi_startproc
.rept 300000
nop
.endr
ret x30
.cfi_endproc
.size large_function, .-large_function

## Force relocation mode.
.reloc 0, R_AARCH64_NONE
61 changes: 61 additions & 0 deletions bolt/test/AArch64/spurious-marker-symbol.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Check that marker symbols ($d, $x) denoting data embedded in code are ignored
// if they fall outside their respective sections.

// RUN: yaml2obj %S/Inputs/spurious-marker-symbol.yaml -o %t.exe
// RUN: llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
// CHECK: 1 out of 1 functions were overwritten
// RUN: llvm-objdump -j .text -d %t.bolt | FileCheck %s -check-prefix=CHECK-DISASM
// CHECK-DISASM: func
// CHECK-DISASM: 2a0000: d2800540 mov
// CHECK-DISASM: 2a0004: d65f03c0 ret

// The YAML encodes the following assembly and debug information:

.text
.globl func
.type func, %function
func:
mov x0, #42
// $d.42: (symbol in .ignored, with an address in .text)
ret

// .eh_frame contains minimal DWARF with a CFA operation on the `ret`. BOLT
// should ignore the spurious `$d.42`. If it doesn't, then it will stop
// disassembling after the `mov` and will fail to process the second
// DW_CFA_def_cfa_offset.
//
// CIE
// length: 00000010
// CIE_id: 00000000
// version: 01
// augmentation:
// "zR" 7a 52 00
// - read augmentation data
// - read FDE pointer encoding
// code_alignment_factor: 04
// data_alignment_factor: 78 (-8)
// return_address_register: 1e (r30 / lr)
//
// augmentation data:
// length: 01
// FDE pointers are absptr+sdata4 0b
//
// initial_instructions:
// DW_CFA_def_cfa (31, 0): 0c 1f 00
//
// Encoding: 10000000'00000000'01'7a5200'04'78'1e'10'0b'0c1f00
//
// FDE
// length: 00000014
// CIE_pointer: 00000018 (backwards offset from here to CIE)
// initial_location: 002a0000 (`func` as absptr+sdata4)
// address_range: 00000008
// augmentation data:
// length: 00
// instructions:
// DW_CFA_def_cfa_offset (1) 0e 01
// DW_CFA_advance_loc (1) 41 (`ret` at 0x2a0004)
// DW_CFA_def_cfa_offset (1) 0e 01 Fails unless $d.42 is ignored.
// DW_CFA_nop 00 00
//
// Encoding: 14000000'18000000'00002a00'08000000'000e0141'0e010000
132 changes: 132 additions & 0 deletions bolt/test/X86/callcont-fallthru.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
## Ensures that a call continuation fallthrough count is set when using
## pre-aggregated perf data.

# RUN: %clangxx %cxxflags %s -o %t -Wl,-q -nostdlib
# RUN: link_fdata %s %t %t.pa1 PREAGG
# RUN: link_fdata %s %t %t.pa2 PREAGG2
# RUN: link_fdata %s %t %t.pa3 PREAGG3
# RUN: link_fdata %s %t %t.pa4 PREAGG4

## Check normal case: fallthrough is not LP or secondary entry.
# RUN: llvm-strip --strip-unneeded %t -o %t.exe
# RUN: llvm-bolt %t.exe --pa -p %t.pa1 -o %t.out \
# RUN: --print-cfg --print-only=main | FileCheck %s

## Check that getFallthroughsInTrace correctly handles a trace starting at plt
## call continuation
# RUN: llvm-bolt %t.exe --pa -p %t.pa2 -o %t.out2 \
# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK2

## Check that we don't treat secondary entry points as call continuation sites.
# RUN: llvm-bolt %t --pa -p %t.pa3 -o %t.out \
# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK3

## Check fallthrough to a landing pad case.
# RUN: llvm-bolt %t.exe --pa -p %t.pa4 -o %t.out \
# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK4

.globl foo
.type foo, %function
foo:
pushq %rbp
movq %rsp, %rbp
popq %rbp
Lfoo_ret:
retq
.size foo, .-foo

.globl main
.type main, %function
main:
.Lfunc_begin0:
.cfi_startproc
.cfi_personality 155, DW.ref.__gxx_personality_v0
.cfi_lsda 27, .Lexception0
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
callq puts@PLT
## Target is a call continuation
# PREAGG: B X:0 #Ltmp1# 2 0
# CHECK: callq puts@PLT
# CHECK-NEXT: count: 2

Ltmp1:
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movl %eax, -0x14(%rbp)

Ltmp4:
cmpl $0x0, -0x14(%rbp)
je Ltmp0
# CHECK2: je .Ltmp0
# CHECK2-NEXT: count: 3

movl $0xa, -0x18(%rbp)
callq foo
## Target is a call continuation
# PREAGG: B #Lfoo_ret# #Ltmp3# 1 0
# CHECK: callq foo
# CHECK-NEXT: count: 1

## PLT call continuation fallthrough spanning the call
# PREAGG2: F #Ltmp1# #Ltmp3_br# 3
# CHECK2: callq foo
# CHECK2-NEXT: count: 3

## Target is a secondary entry point
# PREAGG3: B X:0 #Ltmp3# 2 0
# CHECK3: callq foo
# CHECK3-NEXT: count: 0

## Target is a landing pad
# PREAGG4: B X:0 #Ltmp3# 2 0
# CHECK4: callq puts@PLT
# CHECK4-NEXT: count: 0

Ltmp3:
cmpl $0x0, -0x18(%rbp)
Ltmp3_br:
jmp Ltmp2

Ltmp2:
movl -0x18(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x18(%rbp)
jmp Ltmp3
jmp Ltmp4
jmp Ltmp1

Ltmp0:
xorl %eax, %eax
addq $0x20, %rsp
popq %rbp
retq
.Lfunc_end0:
.cfi_endproc
.size main, .-main

.section .gcc_except_table,"a",@progbits
.p2align 2, 0x0
GCC_except_table0:
.Lexception0:
.byte 255 # @LPStart Encoding = omit
.byte 255 # @TType Encoding = omit
.byte 1 # Call site Encoding = uleb128
.uleb128 .Lcst_end0-.Lcst_begin0
.Lcst_begin0:
.uleb128 .Lfunc_begin0-.Lfunc_begin0 # >> Call Site 1 <<
.uleb128 .Lfunc_end0-.Lfunc_begin0 # Call between .Lfunc_begin0 and .Lfunc_end0
.uleb128 Ltmp3-.Lfunc_begin0 # jumps to Ltmp3
.byte 0 # has no landing pad
.byte 0 # On action: cleanup
.Lcst_end0:
.p2align 2, 0x0
.hidden DW.ref.__gxx_personality_v0
.weak DW.ref.__gxx_personality_v0
.section .data.DW.ref.__gxx_personality_v0,"awG",@progbits,DW.ref.__gxx_personality_v0,comdat
.p2align 3, 0x0
.type DW.ref.__gxx_personality_v0,@object
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ InMemorySymbolIndex::InMemorySymbolIndex(

std::vector<SymbolAndSignals>
InMemorySymbolIndex::search(llvm::StringRef Identifier) {
auto I = LookupTable.find(std::string(Identifier));
auto I = LookupTable.find(Identifier);
if (I != LookupTable.end())
return I->second;
return {};
Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clang-include-fixer/InMemorySymbolIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class InMemorySymbolIndex : public SymbolIndex {
search(llvm::StringRef Identifier) override;

private:
std::map<std::string, std::vector<find_all_symbols::SymbolAndSignals>>
std::map<std::string, std::vector<find_all_symbols::SymbolAndSignals>,
std::less<>>
LookupTable;
};

Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clang-tidy/abseil/DurationRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ std::optional<DurationScale> getScaleForDurationInverse(llvm::StringRef Name) {
{"ToDoubleNanoseconds", DurationScale::Nanoseconds},
{"ToInt64Nanoseconds", DurationScale::Nanoseconds}});

auto ScaleIter = ScaleMap.find(std::string(Name));
auto ScaleIter = ScaleMap.find(Name);
if (ScaleIter == ScaleMap.end())
return std::nullopt;

Expand All @@ -260,7 +260,7 @@ std::optional<DurationScale> getScaleForTimeInverse(llvm::StringRef Name) {
{"ToUnixMicros", DurationScale::Microseconds},
{"ToUnixNanos", DurationScale::Nanoseconds}});

auto ScaleIter = ScaleMap.find(std::string(Name));
auto ScaleIter = ScaleMap.find(Name);
if (ScaleIter == ScaleMap.end())
return std::nullopt;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {

void ThrowKeywordMissingCheck::registerMatchers(MatchFinder *Finder) {
auto CtorInitializerList =
cxxConstructorDecl(hasAnyConstructorInitializer(anything()));

Finder->addMatcher(
cxxConstructExpr(
hasType(cxxRecordDecl(
Expand All @@ -27,7 +24,7 @@ void ThrowKeywordMissingCheck::registerMatchers(MatchFinder *Finder) {
stmt(anyOf(cxxThrowExpr(), callExpr(), returnStmt()))),
hasAncestor(decl(anyOf(varDecl(), fieldDecl()))),
hasAncestor(expr(cxxNewExpr(hasAnyPlacementArg(anything())))),
allOf(hasAncestor(CtorInitializerList),
allOf(hasAncestor(cxxConstructorDecl()),
unless(hasAncestor(cxxCatchStmt()))))))
.bind("temporary-exception-not-thrown"),
this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@

#include "InitVariablesCheck.h"

#include "../utils/LexerUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include <optional>

Expand Down Expand Up @@ -107,8 +108,9 @@ void InitVariablesCheck::check(const MatchFinder::MatchResult &Result) {
<< MatchedDecl;
if (*InitializationString != nullptr)
Diagnostic << FixItHint::CreateInsertion(
MatchedDecl->getLocation().getLocWithOffset(
MatchedDecl->getName().size()),
utils::lexer::findNextTerminator(MatchedDecl->getLocation(),
*Result.SourceManager,
Result.Context->getLangOpts()),
*InitializationString);
if (AddMathInclude) {
Diagnostic << IncludeInserter.createIncludeInsertion(
Expand Down
14 changes: 11 additions & 3 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ Changes in existing checks
usages of ``sizeof()``, ``alignof()``, and ``offsetof()`` when adding or
subtracting from a pointer directly or when used to scale a numeric value.

- Improved :doc:`bugprone-throw-keyword-missing
<clang-tidy/checks/bugprone/throw-keyword-missing>` by fixing a false positive
when using non-static member initializers and a constructor.

- Improved :doc:`bugprone-unchecked-optional-access
<clang-tidy/checks/bugprone/unchecked-optional-access>` to support
`bsl::optional` and `bdlb::NullableValue` from
Expand All @@ -190,6 +194,10 @@ Changes in existing checks
fix false positive that floating point variable is only used in increment
expression.

- Improved :doc:`cppcoreguidelines-init-variables
<clang-tidy/checks/cppcoreguidelines/init-variables>` check by fixing the
insertion location for function pointers.

- Improved :doc:`cppcoreguidelines-prefer-member-initializer
<clang-tidy/checks/cppcoreguidelines/prefer-member-initializer>` check to
avoid false positive when member initialization depends on a structured
Expand All @@ -208,9 +216,9 @@ Changes in existing checks
false positive for C++23 deducing this.

- Improved :doc:`modernize-avoid-c-arrays
<clang-tidy/checks/modernize/avoid-c-arrays>` check to suggest using ``std::span``
as a replacement for parameters of incomplete C array type in C++20 and
``std::array`` or ``std::vector`` before C++20.
<clang-tidy/checks/modernize/avoid-c-arrays>` check to suggest using
``std::span`` as a replacement for parameters of incomplete C array type in
C++20 and ``std::array`` or ``std::vector`` before C++20.

- Improved :doc:`modernize-loop-convert
<clang-tidy/checks/modernize/loop-convert>` check to fix false positive when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,15 @@ CtorInitializerListTest::CtorInitializerListTest(float) try : exc(RegularExcepti
RegularException();
}

namespace GH115055 {
class CtorInitializerListTest2 {
public:
CtorInitializerListTest2() {}
private:
RegularException exc{};
};
} // namespace GH115055

RegularException funcReturningExceptionTest(int i) {
return RegularException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,17 @@ void test_clang_diagnostic_error() {
// CHECK-MESSAGES: :[[@LINE-1]]:3: error: unknown type name 'UnknownType' [clang-diagnostic-error]
// CHECK-FIXES-NOT: {{^}} UnknownType b = 0;{{$}}
}

namespace gh112089 {
void foo(void*);
using FPtr = void(*)(void*);
void test() {
void(*a1)(void*);
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: variable 'a1' is not initialized [cppcoreguidelines-init-variables]
// CHECK-FIXES: void(*a1)(void*) = nullptr;
FPtr a2;
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: variable 'a2' is not initialized [cppcoreguidelines-init-variables]
// CHECK-FIXES: FPtr a2 = nullptr;
}
} // namespace gh112089

96 changes: 96 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3774,6 +3774,74 @@ type-generic alternative to the ``__builtin_clz{,l,ll}`` (respectively
``__builtin_ctz{,l,ll}``) builtins, with support for other integer types, such
as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
``__builtin_counted_by_ref``
----------------------------
``__builtin_counted_by_ref`` returns a pointer to the count field from the
``counted_by`` attribute.
The argument must be a flexible array member. If the argument isn't a flexible
array member or doesn't have the ``counted_by`` attribute, the builtin returns
``(void *)0``.
**Syntax**:
.. code-block:: c
T *__builtin_counted_by_ref(void *array)
**Examples**:
.. code-block:: c
#define alloc(P, FAM, COUNT) ({ \
size_t __ignored_assignment; \
typeof(P) __p = NULL; \
__p = malloc(MAX(sizeof(*__p), \
sizeof(*__p) + sizeof(*__p->FAM) * COUNT)); \
\
*_Generic( \
__builtin_counted_by_ref(__p->FAM), \
void *: &__ignored_assignment, \
default: __builtin_counted_by_ref(__p->FAM)) = COUNT; \
\
__p; \
})
**Description**:
The ``__builtin_counted_by_ref`` builtin allows the programmer to prevent a
common error associated with the ``counted_by`` attribute. When using the
``counted_by`` attribute, the ``count`` field **must** be set before the
flexible array member can be accessed. Otherwise, the sanitizers may view such
accesses as false positives. For instance, it's not uncommon for programmers to
initialize the flexible array before setting the ``count`` field:
.. code-block:: c
struct s {
int dummy;
short count;
long array[] __attribute__((counted_by(count)));
};
struct s *ptr = malloc(sizeof(struct s) + sizeof(long) * COUNT);
for (int i = 0; i < COUNT; ++i)
ptr->array[i] = i;
ptr->count = COUNT;
Enforcing the rule that ``ptr->count = COUNT;`` must occur after every
allocation of a struct with a flexible array member with the ``counted_by``
attribute is prone to failure in large code bases. This builtin mitigates this
for allocators (like in Linux) that are implemented in a way where the counter
assignment can happen automatically.
**Note:** The value returned by ``__builtin_counted_by_ref`` cannot be assigned
to a variable, have its address taken, or passed into or returned from a
function, because doing so violates bounds safety conventions.
Multiprecision Arithmetic Builtins
----------------------------------
Expand Down Expand Up @@ -5906,3 +5974,31 @@ Clang guarantees the following behaviors:
padding bits are initialized to zero.
Currently, the above extension only applies to C source code, not C++.
Empty Objects in C
==================
The declaration of a structure or union type which has no named members is
undefined behavior (C23 and earlier) or implementation-defined behavior (C2y).
Clang allows the declaration of a structure or union type with no named members
in all C language modes. `sizeof` for such a type returns `0`, which is
different behavior than in C++ (where the size of such an object is typically
`1`).
Qualified function types in C
=============================
Declaring a function with a qualified type in C is undefined behavior (C23 and
earlier) or implementation-defined behavior (C2y). Clang allows a function type
to be specified with the ``const`` and ``volatile`` qualifiers, but ignores the
qualifications.
.. code-block:: c
typedef int f(void);
const volatile f func; // Qualifier on function type has no effect.
Note, Clang does not allow an ``_Atomic`` function type because
of explicit constraints against atomically qualified (arrays and) function
types.
2 changes: 2 additions & 0 deletions clang/docs/OpenMPSupport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ implementation.
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| memory management | alignment for allocate directive and clause | :good:`done` | D115683 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| memory management | 'allocator' modifier for allocate clause | :good:`done` | https://github.com/llvm/llvm-project/pull/114883 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| memory management | new memory management routines | :none:`unclaimed` | |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| memory management | changes to omp_alloctrait_key enum | :none:`unclaimed` | |
Expand Down
74 changes: 69 additions & 5 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ C++ Specific Potentially Breaking Changes
unsigned operator""_udl_name(unsigned long long);

- Clang will now produce an error diagnostic when [[clang::lifetimebound]] is
applied on a parameter of a function that returns void. This was previously
ignored and had no effect. (#GH107556)
applied on a parameter or an implicit object parameter of a function that
returns void. This was previously ignored and had no effect. (#GH107556)

.. code-block:: c++

Expand Down Expand Up @@ -274,6 +274,46 @@ C Language Changes
C2y Feature Support
^^^^^^^^^^^^^^^^^^^

- Updated conformance for `N3298 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3298.htm>`_
which adds the ``i`` and ``j`` suffixes for the creation of a ``_Complex``
constant value. Clang has always supported these suffixes as a GNU extension,
so ``-Wgnu-imaginary-constant`` no longer has effect in C modes, as this is
not a C2y extension in C. ``-Wgnu-imaginary-constant`` still applies in C++
modes.

- Clang updated conformance for `N3370 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3370.htm>`_
case range expressions. This feature was previously supported by Clang as a
GNU extension, so ``-Wgnu-case-range`` no longer has effect in C modes, as
this is now a C2y extension in C. ``-Wgnu-case-range`` still applies in C++
modes.

- Clang implemented support for `N3344 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf>`_
which disallows a ``void`` parameter from having a qualifier or storage class
specifier. Note that ``register void`` was previously accepted in all C
language modes but is now rejected (all of the other qualifiers and storage
class specifiers were previously rejected).

- Updated conformance for `N3364 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3364.pdf>`_
on floating-point translation-time initialization with signaling NaN. This
paper adopts Clang's existing practice, so there were no changes to compiler
behavior.

- Implemented support for `N3341 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3341.pdf>`_
which makes empty structure and union objects implementation-defined in C.
``-Wgnu-empty-struct`` will be emitted in C23 and earlier modes because the
behavior is a conforming GNU extension in those modes, but will no longer
have an effect in C2y mode.

- Updated conformance for `N3342 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3342.pdf>`_
which made qualified function types implementation-defined rather than
undefined. Clang has always accepted ``const`` and ``volatile`` qualified
function types by ignoring the qualifiers.

- Updated conformance for `N3346 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3346.pdf>`_
which changes some undefined behavior around initialization to instead be
constraint violations. This paper adopts Clang's existing practice, so there
were no changes to compiler behavior.

C23 Feature Support
^^^^^^^^^^^^^^^^^^^

Expand All @@ -289,6 +329,29 @@ Non-comprehensive list of changes in this release
as well as declarations.
- ``__builtin_abs`` function can now be used in constant expressions.

- The new builtin ``__builtin_counted_by_ref`` was added. In contexts where the
programmer needs access to the ``counted_by`` attribute's field, but it's not
available --- e.g. in macros. For instace, it can be used to automatically
set the counter during allocation in the Linux kernel:

.. code-block:: c
/* A simplified version of Linux allocation macros */
#define alloc(PTR, FAM, COUNT) ({ \
sizeof_t __ignored_assignment; \
typeof(P) __p; \
size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
__p = malloc(__size); \
*_Generic( \
__builtin_counted_by_ref(__p->FAM), \
void *: &__ignored_assignment, \
default: __builtin_counted_by_ref(__p->FAM)) = COUNT; \
__p; \
})
The flexible array member (FAM) can now be accessed immediately without causing
issues with the sanitizer because the counter is automatically set.

New Compiler Flags
------------------

Expand Down Expand Up @@ -569,9 +632,6 @@ Bug Fixes to C++ Support
in certain friend declarations. (#GH93099)
- Clang now instantiates the correct lambda call operator when a lambda's class type is
merged across modules. (#GH110401)
- Clang now uses the correct set of template argument lists when comparing the constraints of
out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of
a class template. (#GH102320)
- Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460)
- Fixed an assertion failure when invoking recovery call expressions with explicit attributes
and undeclared templates. (#GH107047), (#GH49093)
Expand All @@ -591,6 +651,7 @@ Bug Fixes to C++ Support
- Clang now correctly ignores previous partial specializations of member templates explicitly specialized for
an implicitly instantiated class template specialization. (#GH51051)
- Fixed an assertion failure caused by invalid enum forward declarations. (#GH112208)
- Name independent data members were not correctly initialized from default member initializers. (#GH114069)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -678,6 +739,7 @@ X86 Support
* Supported intrinsics of ``_mm(256|512)_(mask(z))_loadrs_epi(8|16|32|64)``.
- Support ISA of ``AMX-FP8``.
- Support ISA of ``AMX-TRANSPOSE``.
- Support ISA of ``AMX-AVX512``.

Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -716,6 +778,7 @@ CUDA Support
^^^^^^^^^^^^
- Clang now supports CUDA SDK up to 12.6
- Added support for sm_100
- Added support for `__grid_constant__` attribute.

AIX Support
^^^^^^^^^^^
Expand Down Expand Up @@ -887,6 +950,7 @@ OpenMP Support
--------------
- Added support for 'omp assume' directive.
- Added support for 'omp scope' directive.
- Added support for allocator-modifier in 'allocate' clause.

Improvements
^^^^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion clang/docs/SafeBuffers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ A relatively fresh version of C++ is recommended. In particular, the very useful
standard view class ``std::span`` requires C++20.

Other implementations of the C++ standard library may provide different
flags to enable such hardening hardening.
flags to enable such hardening.

If you're using custom containers and views, they will need to be hardened
this way as well, but you don't necessarily need to do this ahead of time.
Expand Down
9 changes: 4 additions & 5 deletions clang/docs/ShadowCallStack.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,10 @@ and destruction would need to be intercepted by the application.

The instrumentation makes use of the platform register ``x18`` on AArch64,
``x3`` (``gp``) on RISC-V with software shadow stack and ``ssp`` on RISC-V with
hardware shadow stack, which needs `Zicfiss`_ and ``-mno-forced-sw-shadow-stack``
(default option). Note that with ``Zicfiss``_ the RISC-V backend will default to
the hardware based shadow call stack. Users can force the RISC-V backend to
generate the software shadow call stack with ``Zicfiss``_ by passing
``-mforced-sw-shadow-stack``.
hardware shadow stack, which needs `Zicfiss`_ and ``-fcf-protection=return``.
Users can choose between the software and hardware based shadow stack
implementation on RISC-V backend by passing ``-fsanitize=shadowcallstack``
or ``Zicfiss`` with ``-fcf-protection=return``.
For simplicity we will refer to this as the ``SCSReg``. On some platforms,
``SCSReg`` is reserved, and on others, it is designated as a scratch register.
This generally means that any code that may run on the same thread as code
Expand Down
6 changes: 6 additions & 0 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3560,6 +3560,12 @@ We also define a set of safe transformations which if passed a safe value as an
- casts
- unary operators like ``&`` or ``*``
alpha.webkit.UncheckedCallArgsChecker
"""""""""""""""""""""""""""""""""""""
The goal of this rule is to make sure that lifetime of any dynamically allocated CheckedPtr capable object passed as a call argument keeps its memory region past the end of the call. This applies to call to any function, method, lambda, function pointer or functor. CheckedPtr capable objects aren't supposed to be allocated on stack so we check arguments for parameters of raw pointers and references to unchecked types.
The rules of when to use and not to use CheckedPtr / CheckedRef are same as alpha.webkit.UncountedCallArgsChecker for ref-counted objects.
alpha.webkit.UncountedLocalVarsChecker
""""""""""""""""""""""""""""""""""""""
The goal of this rule is to make sure that any uncounted local variable is backed by a ref-counted object with lifetime that is strictly larger than the scope of the uncounted local variable. To be on the safe side we require the scope of an uncounted variable to be embedded in the scope of ref-counted object that backs it.
Expand Down
25 changes: 18 additions & 7 deletions clang/include/clang/APINotes/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -445,19 +445,16 @@ class ParamInfo : public VariableInfo {
RawRetainCountConvention() {}

std::optional<bool> isNoEscape() const {
if (!NoEscapeSpecified)
return std::nullopt;
return NoEscape;
return NoEscapeSpecified ? std::optional<bool>(NoEscape) : std::nullopt;
}
void setNoEscape(std::optional<bool> Value) {
NoEscapeSpecified = Value.has_value();
NoEscape = Value.value_or(false);
}

std::optional<bool> isLifetimebound() const {
if (!LifetimeboundSpecified)
return std::nullopt;
return Lifetimebound;
return LifetimeboundSpecified ? std::optional<bool>(Lifetimebound)
: std::nullopt;
}
void setLifetimebound(std::optional<bool> Value) {
LifetimeboundSpecified = Value.has_value();
Expand Down Expand Up @@ -643,6 +640,8 @@ class ObjCMethodInfo : public FunctionInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned RequiredInit : 1;

std::optional<ParamInfo> Self;

ObjCMethodInfo() : DesignatedInit(false), RequiredInit(false) {}

friend bool operator==(const ObjCMethodInfo &, const ObjCMethodInfo &);
Expand All @@ -664,7 +663,7 @@ class ObjCMethodInfo : public FunctionInfo {
inline bool operator==(const ObjCMethodInfo &LHS, const ObjCMethodInfo &RHS) {
return static_cast<const FunctionInfo &>(LHS) == RHS &&
LHS.DesignatedInit == RHS.DesignatedInit &&
LHS.RequiredInit == RHS.RequiredInit;
LHS.RequiredInit == RHS.RequiredInit && LHS.Self == RHS.Self;
}

inline bool operator!=(const ObjCMethodInfo &LHS, const ObjCMethodInfo &RHS) {
Expand Down Expand Up @@ -693,8 +692,20 @@ class FieldInfo : public VariableInfo {
class CXXMethodInfo : public FunctionInfo {
public:
CXXMethodInfo() {}

std::optional<ParamInfo> This;

LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS);
};

inline bool operator==(const CXXMethodInfo &LHS, const CXXMethodInfo &RHS) {
return static_cast<const FunctionInfo &>(LHS) == RHS && LHS.This == RHS.This;
}

inline bool operator!=(const CXXMethodInfo &LHS, const CXXMethodInfo &RHS) {
return !(LHS == RHS);
}

/// Describes API notes data for an enumerator.
class EnumConstantInfo : public CommonEntityInfo {
public:
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1041,7 +1041,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst,
UsingShadowDecl *Pattern);

FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) const;

void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);

Expand Down Expand Up @@ -1747,7 +1747,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType
getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
unsigned Index,
std::optional<unsigned> PackIndex) const;
std::optional<unsigned> PackIndex,
SubstTemplateTypeParmTypeFlag Flag =
SubstTemplateTypeParmTypeFlag::None) const;
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
unsigned Index, bool Final,
const TemplateArgument &ArgPack);
Expand Down
83 changes: 51 additions & 32 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -787,11 +787,15 @@ class RedeclarableTemplateDecl : public TemplateDecl,
EntryType *Entry, void *InsertPos);

struct CommonBase {
CommonBase() {}
CommonBase() : InstantiatedFromMember(nullptr, false) {}

/// The template from which this was most
/// directly instantiated (or null).
RedeclarableTemplateDecl *InstantiatedFromMember = nullptr;
///
/// The boolean value indicates whether this template
/// was explicitly specialized.
llvm::PointerIntPair<RedeclarableTemplateDecl *, 1, bool>
InstantiatedFromMember;

/// If non-null, points to an array of specializations (including
/// partial specializations) known only by their external declaration IDs.
Expand All @@ -802,19 +806,14 @@ class RedeclarableTemplateDecl : public TemplateDecl,
};

/// Pointer to the common data shared by all declarations of this
/// template, and a flag indicating if the template is a member
/// specialization.
mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common;

CommonBase *getCommonPtrInternal() const { return Common.getPointer(); }
/// template.
mutable CommonBase *Common = nullptr;

/// Retrieves the "common" pointer shared by all (re-)declarations of
/// the same template. Calling this routine may implicitly allocate memory
/// for the common pointer.
CommonBase *getCommonPtr() const;

void setCommonPtr(CommonBase *C) const { Common.setPointer(C); }

virtual CommonBase *newCommon(ASTContext &C) const = 0;

// Construct a template decl with name, parameters, and templated element.
Expand Down Expand Up @@ -855,12 +854,15 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// template<> template<typename T>
/// struct X<int>::Inner { /* ... */ };
/// \endcode
bool isMemberSpecialization() const { return Common.getInt(); }
bool isMemberSpecialization() const {
return getCommonPtr()->InstantiatedFromMember.getInt();
}

/// Note that this member template is a specialization.
void setMemberSpecialization() {
assert(!isMemberSpecialization() && "already a member specialization");
Common.setInt(true);
assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations");
getCommonPtr()->InstantiatedFromMember.setInt(true);
}

/// Retrieve the member template from which this template was
Expand Down Expand Up @@ -900,12 +902,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// void X<T>::f(T, U);
/// \endcode
RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
return getCommonPtr()->InstantiatedFromMember;
return getCommonPtr()->InstantiatedFromMember.getPointer();
}

void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
assert(!getCommonPtr()->InstantiatedFromMember);
getCommonPtr()->InstantiatedFromMember = TD;
assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
getCommonPtr()->InstantiatedFromMember.setPointer(TD);
}

/// Retrieve the "injected" template arguments that correspond to the
Expand Down Expand Up @@ -1955,7 +1957,13 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
/// specialization which was specialized by this.
llvm::PointerUnion<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>
getSpecializedTemplateOrPartial() const;
getSpecializedTemplateOrPartial() const {
if (const auto *PartialSpec =
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
return PartialSpec->PartialSpecialization;

return SpecializedTemplate.get<ClassTemplateDecl*>();
}

/// Retrieve the set of template arguments that should be used
/// to instantiate members of the class template or class template partial
Expand All @@ -1981,8 +1989,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
/// template arguments have been deduced.
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgumentList *TemplateArgs) {
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
"A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
"Already set to a class template partial specialization!");
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
Expand All @@ -1994,8 +2000,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
/// Note that this class template specialization is an instantiation
/// of the given class template.
void setInstantiationOf(ClassTemplateDecl *TemplDecl) {
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
"A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
"Previously set to a class template partial specialization!");
SpecializedTemplate = TemplDecl;
Expand Down Expand Up @@ -2189,11 +2193,18 @@ class ClassTemplatePartialSpecializationDecl
/// struct X<int>::Inner<T*> { /* ... */ };
/// \endcode
bool isMemberSpecialization() const {
return InstantiatedFromMember.getInt();
const auto *First =
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getInt();
}

/// Note that this member template is a specialization.
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
void setMemberSpecialization() {
auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
assert(First->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations");
return First->InstantiatedFromMember.setInt(true);
}

/// Retrieves the injected specialization type for this partial
/// specialization. This is not the same as the type-decl-type for
Expand Down Expand Up @@ -2263,6 +2274,8 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
}

void setCommonPtr(Common *C) { RedeclarableTemplateDecl::Common = C; }

public:

friend class ASTDeclReader;
Expand Down Expand Up @@ -2713,7 +2726,13 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// Retrieve the variable template or variable template partial
/// specialization which was specialized by this.
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
getSpecializedTemplateOrPartial() const;
getSpecializedTemplateOrPartial() const {
if (const auto *PartialSpec =
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
return PartialSpec->PartialSpecialization;

return SpecializedTemplate.get<VarTemplateDecl *>();
}

/// Retrieve the set of template arguments that should be used
/// to instantiate the initializer of the variable template or variable
Expand All @@ -2739,8 +2758,6 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// template arguments have been deduced.
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgumentList *TemplateArgs) {
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
"A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
"Already set to a variable template partial specialization!");
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
Expand All @@ -2752,8 +2769,6 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// Note that this variable template specialization is an instantiation
/// of the given variable template.
void setInstantiationOf(VarTemplateDecl *TemplDecl) {
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
"A partial specialization cannot be instantiated from a template");
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
"Previously set to a variable template partial specialization!");
SpecializedTemplate = TemplDecl;
Expand Down Expand Up @@ -2944,11 +2959,18 @@ class VarTemplatePartialSpecializationDecl
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
/// \endcode
bool isMemberSpecialization() const {
return InstantiatedFromMember.getInt();
const auto *First =
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getInt();
}

/// Note that this member template is a specialization.
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
void setMemberSpecialization() {
auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
assert(First->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations");
return First->InstantiatedFromMember.setInt(true);
}

SourceRange getSourceRange() const override LLVM_READONLY;

Expand Down Expand Up @@ -3119,9 +3141,6 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
return makeSpecIterator(getSpecializations(), true);
}

/// Merge \p Prev with our RedeclarableTemplateDecl::Common.
void mergePrevDecl(VarTemplateDecl *Prev);

// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == VarTemplate; }
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -4326,6 +4326,8 @@ class SizeOfPackExpr final
/// Retrieve the parameter pack.
NamedDecl *getPack() const { return Pack; }

void setPack(NamedDecl *NewPack) { Pack = NewPack; }

/// Retrieve the length of the parameter pack.
///
/// This routine may only be invoked when the expression is not
Expand Down
39 changes: 32 additions & 7 deletions clang/include/clang/AST/OpenMPClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,8 @@ class OMPAlignClause final
/// #pragma omp parallel private(a) allocate(omp_default_mem_alloc :a)
/// \endcode
/// In this example directive '#pragma omp parallel' has clause 'private'
/// and clause 'allocate' for the variable 'a'.
/// and clause 'allocate' for the variable 'a', which specifies an explicit
/// memory allocator.
class OMPAllocateClause final
: public OMPVarListClause<OMPAllocateClause>,
private llvm::TrailingObjects<OMPAllocateClause, Expr *> {
Expand All @@ -499,6 +500,10 @@ class OMPAllocateClause final
Expr *Allocator = nullptr;
/// Position of the ':' delimiter in the clause;
SourceLocation ColonLoc;
/// Modifier of 'allocate' clause.
OpenMPAllocateClauseModifier AllocatorModifier = OMPC_ALLOCATE_unknown;
/// Location of allocator modifier if any.
SourceLocation AllocatorModifierLoc;

/// Build clause with number of variables \a N.
///
Expand All @@ -510,10 +515,14 @@ class OMPAllocateClause final
/// \param N Number of the variables in the clause.
OMPAllocateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
Expr *Allocator, SourceLocation ColonLoc,
SourceLocation EndLoc, unsigned N)
OpenMPAllocateClauseModifier AllocatorModifier,
SourceLocation AllocatorModifierLoc, SourceLocation EndLoc,
unsigned N)
: OMPVarListClause<OMPAllocateClause>(llvm::omp::OMPC_allocate, StartLoc,
LParenLoc, EndLoc, N),
Allocator(Allocator), ColonLoc(ColonLoc) {}
Allocator(Allocator), ColonLoc(ColonLoc),
AllocatorModifier(AllocatorModifier),
AllocatorModifierLoc(AllocatorModifierLoc) {}

/// Build an empty clause.
///
Expand All @@ -527,6 +536,9 @@ class OMPAllocateClause final
void setColonLoc(SourceLocation CL) { ColonLoc = CL; }

void setAllocator(Expr *A) { Allocator = A; }
void setAllocatorModifier(OpenMPAllocateClauseModifier AM) {
AllocatorModifier = AM;
}

public:
/// Creates clause with a list of variables \a VL.
Expand All @@ -536,18 +548,31 @@ class OMPAllocateClause final
/// \param LParenLoc Location of '('.
/// \param Allocator Allocator expression.
/// \param ColonLoc Location of ':' delimiter.
/// \param AllocatorModifier Allocator modifier.
/// \param SourceLocation Allocator modifier location.
/// \param EndLoc Ending location of the clause.
/// \param VL List of references to the variables.
static OMPAllocateClause *Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc, Expr *Allocator,
SourceLocation ColonLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL);
static OMPAllocateClause *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
Expr *Allocator, SourceLocation ColonLoc,
OpenMPAllocateClauseModifier AllocatorModifier,
SourceLocation AllocatorModifierLoc, SourceLocation EndLoc,
ArrayRef<Expr *> VL);

/// Returns the allocator expression or nullptr, if no allocator is specified.
Expr *getAllocator() const { return Allocator; }

/// Return 'allocate' modifier.
OpenMPAllocateClauseModifier getAllocatorModifier() const {
return AllocatorModifier;
}

/// Returns the location of the ':' delimiter.
SourceLocation getColonLoc() const { return ColonLoc; }
/// Return the location of the modifier.
SourceLocation getAllocatorModifierLoc() const {
return AllocatorModifierLoc;
}

/// Creates an empty clause with the place for \a N variables.
///
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def Selector : PropertyType;
def SourceLocation : PropertyType;
def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; }
def ExprRef : SubclassPropertyType<"Expr", StmtRef>;
def SubstTemplateTypeParmTypeFlag : EnumPropertyType;
def TemplateArgument : PropertyType;
def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">;
def TemplateName : DefaultValuePropertyType;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/SYCLKernelInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_AST_SYCLKERNELINFO_H
#define LLVM_CLANG_AST_SYCLKERNELINFO_H

#include "clang/AST/CanonicalType.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"

Expand Down
37 changes: 14 additions & 23 deletions clang/include/clang/AST/StmtOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt {
}
};

class OpenACCLoopConstruct;
/// This class represents a compute construct, representing a 'Kind' of
/// `parallel', 'serial', or 'kernel'. These constructs are associated with a
/// 'structured block', defined as:
Expand Down Expand Up @@ -183,8 +182,7 @@ class OpenACCComputeConstruct final
static OpenACCComputeConstruct *
Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,
SourceLocation DirectiveLoc, SourceLocation EndLoc,
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock,
ArrayRef<OpenACCLoopConstruct *> AssociatedLoopConstructs);
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock);

Stmt *getStructuredBlock() { return getAssociatedStmt(); }
const Stmt *getStructuredBlock() const {
Expand All @@ -198,12 +196,10 @@ class OpenACCLoopConstruct final
: public OpenACCAssociatedStmtConstruct,
public llvm::TrailingObjects<OpenACCLoopConstruct,
const OpenACCClause *> {
// The compute construct this loop is associated with, or nullptr if this is
// an orphaned loop construct, or if it hasn't been set yet. Because we
// construct the directives at the end of their statement, the 'parent'
// construct is not yet available at the time of construction, so this needs
// to be set 'later'.
const OpenACCComputeConstruct *ParentComputeConstruct = nullptr;
// The compute/combined construct kind this loop is associated with, or
// invalid if this is an orphaned loop construct.
OpenACCDirectiveKind ParentComputeConstructKind =
OpenACCDirectiveKind::Invalid;

friend class ASTStmtWriter;
friend class ASTStmtReader;
Expand All @@ -212,15 +208,9 @@ class OpenACCLoopConstruct final

OpenACCLoopConstruct(unsigned NumClauses);

OpenACCLoopConstruct(SourceLocation Start, SourceLocation DirLoc,
SourceLocation End,
OpenACCLoopConstruct(OpenACCDirectiveKind ParentKind, SourceLocation Start,
SourceLocation DirLoc, SourceLocation End,
ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop);
void setLoop(Stmt *Loop);

void setParentComputeConstruct(OpenACCComputeConstruct *CC) {
assert(!ParentComputeConstruct && "Parent already set?");
ParentComputeConstruct = CC;
}

public:
static bool classof(const Stmt *T) {
Expand All @@ -231,9 +221,9 @@ class OpenACCLoopConstruct final
unsigned NumClauses);

static OpenACCLoopConstruct *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation DirLoc,
SourceLocation EndLoc, ArrayRef<const OpenACCClause *> Clauses,
Stmt *Loop);
Create(const ASTContext &C, OpenACCDirectiveKind ParentKind,
SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation EndLoc,
ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop);

Stmt *getLoop() { return getAssociatedStmt(); }
const Stmt *getLoop() const {
Expand All @@ -246,10 +236,11 @@ class OpenACCLoopConstruct final
/// loop construct is the nearest compute construct that lexically contains
/// the loop construct.
bool isOrphanedLoopConstruct() const {
return ParentComputeConstruct == nullptr;
return ParentComputeConstructKind == OpenACCDirectiveKind::Invalid;
}
const OpenACCComputeConstruct *getParentComputeConstruct() const {
return ParentComputeConstruct;

OpenACCDirectiveKind getParentComputeConstructKind() const {
return ParentComputeConstructKind;
}
};
} // namespace clang
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/AST/TemplateArgumentVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class Base {
#define VISIT_METHOD(CATEGORY) \
RetTy Visit##CATEGORY##TemplateArgument(REF(TemplateArgument) TA, \
ParamTys... P) { \
return VisitTemplateArgument(TA, std::forward<ParamTys>(P)...); \
return static_cast<ImplClass *>(this)->VisitTemplateArgument( \
TA, std::forward<ParamTys>(P)...); \
}

VISIT_METHOD(Null);
Expand Down
29 changes: 26 additions & 3 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -1802,6 +1802,15 @@ enum class AutoTypeKeyword {
GNUAutoType
};

enum class SubstTemplateTypeParmTypeFlag {
None,

/// Whether to expand the pack using the stored PackIndex in place. This is
/// useful for e.g. substituting into an atomic constraint expression, where
/// that expression is part of an unexpanded pack.
ExpandPacksInPlace,
};

enum class ArraySizeModifier;
enum class ElaboratedTypeKeyword;
enum class VectorKind;
Expand Down Expand Up @@ -2171,6 +2180,9 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
LLVM_PREFERRED_TYPE(bool)
unsigned HasNonCanonicalUnderlyingType : 1;

LLVM_PREFERRED_TYPE(SubstTemplateTypeParmTypeFlag)
unsigned SubstitutionFlag : 1;

// The index of the template parameter this substitution represents.
unsigned Index : 15;

Expand Down Expand Up @@ -6387,7 +6399,8 @@ class SubstTemplateTypeParmType final
Decl *AssociatedDecl;

SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
unsigned Index, std::optional<unsigned> PackIndex);
unsigned Index, std::optional<unsigned> PackIndex,
SubstTemplateTypeParmTypeFlag Flag);

public:
/// Gets the type that was substituted for the template
Expand Down Expand Up @@ -6416,21 +6429,31 @@ class SubstTemplateTypeParmType final
return SubstTemplateTypeParmTypeBits.PackIndex - 1;
}

SubstTemplateTypeParmTypeFlag getSubstitutionFlag() const {
return static_cast<SubstTemplateTypeParmTypeFlag>(
SubstTemplateTypeParmTypeBits.SubstitutionFlag);
}

bool isSugared() const { return true; }
QualType desugar() const { return getReplacementType(); }

void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getReplacementType(), getAssociatedDecl(), getIndex(),
getPackIndex());
getPackIndex(), getSubstitutionFlag());
}

static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement,
const Decl *AssociatedDecl, unsigned Index,
std::optional<unsigned> PackIndex) {
std::optional<unsigned> PackIndex,
SubstTemplateTypeParmTypeFlag Flag) {
Replacement.Profile(ID);
ID.AddPointer(AssociatedDecl);
ID.AddInteger(Index);
ID.AddInteger(PackIndex ? *PackIndex - 1 : 0);
ID.AddInteger(llvm::to_underlying(Flag));
assert((Flag != SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace ||
PackIndex) &&
"ExpandPacksInPlace needs a valid PackIndex");
}

static bool classof(const Type *T) {
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -824,11 +824,14 @@ let Class = SubstTemplateTypeParmType in {
def : Property<"PackIndex", Optional<UInt32>> {
let Read = [{ node->getPackIndex() }];
}
def : Property<"SubstitutionFlag", SubstTemplateTypeParmTypeFlag> {
let Read = [{ node->getSubstitutionFlag() }];
}

// The call to getCanonicalType here existed in ASTReader.cpp, too.
def : Creator<[{
return ctx.getSubstTemplateTypeParmType(
replacementType, associatedDecl, Index, PackIndex);
replacementType, associatedDecl, Index, PackIndex, SubstitutionFlag);
}]>;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -3226,7 +3226,7 @@ AST_MATCHER_P(CXXDependentScopeMemberExpr, memberHasSameNameAsBoundNode,

return Builder->removeBindings(
[this, MemberName](const BoundNodesMap &Nodes) {
const auto &BN = Nodes.getNode(this->BindingID);
const DynTypedNode &BN = Nodes.getNode(this->BindingID);
if (const auto *ND = BN.get<NamedDecl>()) {
if (!isa<FieldDecl, CXXMethodDecl, VarDecl>(ND))
return true;
Expand Down
8 changes: 7 additions & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,13 @@ def CUDAHost : InheritableAttr {
}
def : MutualExclusions<[CUDAGlobal, CUDAHost]>;

def CUDAGridConstant : InheritableAttr {
let Spellings = [GNU<"grid_constant">, Declspec<"__grid_constant__">];
let Subjects = SubjectList<[ParmVar]>;
let LangOpts = [CUDA];
let Documentation = [CUDAGridConstantAttrDocs];
}

def NVPTXKernel : InheritableAttr, TargetSpecificAttr<TargetNVPTX> {
let Spellings = [Clang<"nvptx_kernel">];
let Subjects = SubjectList<[Function]>;
Expand Down Expand Up @@ -1879,7 +1886,6 @@ def LifetimeBound : DeclOrTypeAttr {
let Spellings = [Clang<"lifetimebound", 0>];
let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>;
let Documentation = [LifetimeBoundDocs];
let LangOpts = [CPlusPlus];
let SimpleHandler = 1;
}

Expand Down
13 changes: 11 additions & 2 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3858,8 +3858,7 @@ def LifetimeBoundDocs : Documentation {
The ``lifetimebound`` attribute on a function parameter or implicit object
parameter indicates that objects that are referred to by that parameter may
also be referred to by the return value of the annotated function (or, for a
parameter of a constructor, by the value of the constructed object). It is only
supported in C++.
parameter of a constructor, by the value of the constructed object).

By default, a reference is considered to refer to its referenced object, a
pointer is considered to refer to its pointee, a ``std::initializer_list<T>``
Expand Down Expand Up @@ -6794,6 +6793,16 @@ unbind runtime APIs.
}];
}

def CUDAGridConstantAttrDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
The ``__grid_constant__`` attribute can be applied to a ``const``-qualified kernel
function argument and allows compiler to take the address of that argument without
making a copy. The argument applies to sm_70 or newer GPUs, during compilation
with CUDA-11.7(PTX 7.7) or newer, and is ignored otherwise.
}];
}

def HIPManagedAttrDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/AttributeCommonInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class AttributeCommonInfo {
IgnoredAttribute,
UnknownAttribute,
};
enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, GSL, RISCV };

private:
const IdentifierInfo *AttrName = nullptr;
Expand Down
18 changes: 18 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -4798,6 +4798,18 @@ def HLSLDot4AddI8Packed : LangBuiltin<"HLSL_LANG"> {
let Prototype = "int(unsigned int, unsigned int, int)";
}

def HLSLDot4AddU8Packed : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_dot4add_u8packed"];
let Attributes = [NoThrow, Const];
let Prototype = "unsigned int(unsigned int, unsigned int, unsigned int)";
}

def HLSLFirstBitHigh : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_firstbithigh"];
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}

def HLSLFrac : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_frac"];
let Attributes = [NoThrow, Const];
Expand Down Expand Up @@ -4920,3 +4932,9 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def CountedByRef : Builtin {
let Spellings = ["__builtin_counted_by_ref"];
let Attributes = [NoThrow, CustomTypeChecking];
let Prototype = "int(...)";
}
12 changes: 6 additions & 6 deletions clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -439,15 +439,15 @@ TARGET_BUILTIN(__builtin_amdgcn_s_sleep_var, "vUi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_permlane16_var, "UiUiUiUiIbIb", "nc", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_permlanex16_var, "UiUiUiUiIbIb", "nc", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal, "vIi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_var, "vi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_var, "vv*i", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_wait, "vIs", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_isfirst, "bIi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_isfirst_var, "bi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_init, "vii", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_join, "vi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_wakeup_barrier, "vi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_leave, "b", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_init, "vv*i", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_join, "vv*", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_wakeup_barrier, "vv*", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_leave, "vIs", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_get_barrier_state, "Uii", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_get_named_barrier_state, "Uiv*", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_prefetch_data, "vvC*Ui", "nc", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_buffer_prefetch_data, "vQbIiUi", "nc", "gfx12-insts")

Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Basic/BuiltinsX86_64.def
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ TARGET_BUILTIN(__builtin_ia32_t2rpntlvwz0t1_internal, "vUsUsUsV256i*V256i*vC*z",
TARGET_BUILTIN(__builtin_ia32_t2rpntlvwz1_internal, "vUsUsUsV256i*V256i*vC*z", "n", "amx-transpose")
TARGET_BUILTIN(__builtin_ia32_t2rpntlvwz1t1_internal, "vUsUsUsV256i*V256i*vC*z", "n", "amx-transpose")
TARGET_BUILTIN(__builtin_ia32_ttransposed_internal, "V256iUsUsV256i", "n", "amx-transpose")
TARGET_BUILTIN(__builtin_ia32_tcvtrowd2ps_internal, "V16fUsUsV256iUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tcvtrowps2pbf16h_internal, "V32yUsUsV256iUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tcvtrowps2pbf16l_internal, "V32yUsUsV256iUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tcvtrowps2phh_internal, "V32xUsUsV256iUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tcvtrowps2phl_internal, "V32xUsUsV256iUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tilemovrow_internal, "V16iUsUsV256iUi", "n", "amx-avx512,avx10.2-512")
// AMX
TARGET_BUILTIN(__builtin_ia32_tile_loadconfig, "vvC*", "n", "amx-tile")
TARGET_BUILTIN(__builtin_ia32_tile_storeconfig, "vvC*", "n", "amx-tile")
Expand All @@ -159,6 +165,13 @@ TARGET_BUILTIN(__builtin_ia32_t2rpntlvwz1, "vIUcvC*z", "n", "amx-transpose")
TARGET_BUILTIN(__builtin_ia32_t2rpntlvwz1t1, "vIUcvC*z", "n","amx-transpose")
TARGET_BUILTIN(__builtin_ia32_ttransposed, "vIUcIUc", "n", "amx-transpose")

TARGET_BUILTIN(__builtin_ia32_tcvtrowd2ps, "V16fIUcUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tcvtrowps2pbf16h, "V32yIUcUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tcvtrowps2pbf16l, "V32yIUcUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tcvtrowps2phh, "V32xIUcUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tcvtrowps2phl, "V32xIUcUi", "n", "amx-avx512,avx10.2-512")
TARGET_BUILTIN(__builtin_ia32_tilemovrow, "V16iIUcUi", "n", "amx-avx512,avx10.2-512")

TARGET_BUILTIN(__builtin_ia32_prefetchi, "vvC*Ui", "nc", "prefetchi")
TARGET_BUILTIN(__builtin_ia32_cmpccxadd32, "Siv*SiSiIi", "n", "cmpccxadd")
TARGET_BUILTIN(__builtin_ia32_cmpccxadd64, "SLLiSLLi*SLLiSLLiIi", "n", "cmpccxadd")
Expand Down
11 changes: 6 additions & 5 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -389,13 +389,14 @@ def remark_sloc_usage : Remark<
"source manager location address space usage:">,
InGroup<DiagGroup<"sloc-usage">>, DefaultRemark, ShowInSystemHeader;
def note_total_sloc_usage : Note<
"%0B in local locations, %1B in locations loaded from AST files, for a total "
"of %2B (%3%% of available space)">;
"%0B (%1B) in local locations, %2B (%3B) "
"in locations loaded from AST files, for a total of %4B (%5B) "
"(%6%% of available space)">;
def note_file_sloc_usage : Note<
"file entered %0 time%s0 using %1B of space"
"%plural{0:|: plus %2B for macro expansions}2">;
"file entered %0 time%s0 using %1B (%2B) of space"
"%plural{0:|: plus %3B (%4B) for macro expansions}3">;
def note_file_misc_sloc_usage : Note<
"%0 additional files entered using a total of %1B of space">;
"%0 additional files entered using a total of %1B (%2B) of space">;

// Modules
def err_module_format_unhandled : Error<
Expand Down
9 changes: 7 additions & 2 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,13 @@ def err_expected_equal_designator : Error<"expected '=' or another designator">;
def ext_gnu_old_style_field_designator : ExtWarn<
"use of GNU old-style field designator extension">,
InGroup<GNUDesignator>;
def ext_gnu_case_range : Extension<"use of GNU case range extension">,
InGroup<GNUCaseRange>;
def ext_gnu_case_range : Extension<
"case ranges are a GNU extension">, InGroup<GNUCaseRange>;
def warn_c23_compat_case_range : Warning<
"case ranges are incompatible with C standards before C2y">,
DefaultIgnore, InGroup<CPre2yCompat>;
def ext_c2y_case_range : Extension<
"case ranges are a C2y extension">, InGroup<C2y>;

// Generic errors.
def err_expected_expression : Error<"expected expression">;
Expand Down
37 changes: 34 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -6241,8 +6241,9 @@ def err_typecheck_negative_array_size : Error<"array size is negative">;
def warn_typecheck_function_qualifiers_ignored : Warning<
"'%0' qualifier on function type %1 has no effect">,
InGroup<IgnoredQualifiers>;
def warn_typecheck_function_qualifiers_unspecified : Warning<
"'%0' qualifier on function type %1 has unspecified behavior">;
def ext_typecheck_function_qualifiers_unspecified : ExtWarn<
"'%0' qualifier on function type %1 has no effect and is a Clang extension">,
InGroup<IgnoredQualifiers>;
def warn_typecheck_reference_qualifiers : Warning<
"'%0' qualifier on reference type %1 has no effect">,
InGroup<IgnoredReferenceQualifiers>;
Expand Down Expand Up @@ -6652,6 +6653,18 @@ def warn_counted_by_attr_elt_type_unknown_size :
Warning<err_counted_by_attr_pointee_unknown_size.Summary>,
InGroup<BoundsSafetyCountedByEltTyUnknownSize>;

// __builtin_counted_by_ref diagnostics:
def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
"'__builtin_counted_by_ref' argument must reference a flexible array member">;
def err_builtin_counted_by_ref_cannot_leak_reference : Error<
"value returned by '__builtin_counted_by_ref' cannot be assigned to a "
"variable, have its address taken, or passed into or returned from a function">;
def err_builtin_counted_by_ref_invalid_lhs_use : Error<
"value returned by '__builtin_counted_by_ref' cannot be used in "
"%select{an array subscript|a binary}0 expression">;
def err_builtin_counted_by_ref_has_side_effects : Error<
"'__builtin_counted_by_ref' argument cannot have side-effects">;

let CategoryName = "ARC Semantic Issue" in {

// ARC-mode diagnostics.
Expand Down Expand Up @@ -9100,6 +9113,8 @@ def err_cuda_host_shared : Error<
"%select{__device__|__global__|__host__|__host__ __device__}0 functions">;
def err_cuda_nonstatic_constdev: Error<"__constant__, __device__, and "
"__managed__ are not allowed on non-static local variables">;
def err_cuda_grid_constant_not_allowed : Error<
"__grid_constant__ is only allowed on const-qualified kernel parameters">;
def err_cuda_ovl_target : Error<
"%select{__device__|__global__|__host__|__host__ __device__}0 function %1 "
"cannot overload %select{__device__|__global__|__host__|__host__ __device__}2 function %3">;
Expand Down Expand Up @@ -10101,9 +10116,12 @@ def err_lifetimebound_no_object_param : Error<
def err_lifetimebound_ctor_dtor : Error<
"'lifetimebound' attribute cannot be applied to a "
"%select{constructor|destructor}0">;
def err_lifetimebound_void_return_type : Error<
def err_lifetimebound_parameter_void_return_type : Error<
"'lifetimebound' attribute cannot be applied to a parameter of a function "
"that returns void">;
def err_lifetimebound_implicit_object_parameter_void_return_type : Error<
"'lifetimebound' attribute cannot be applied to an implicit object "
"parameter of a function that returns void">;

// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr_ref : Warning<
Expand Down Expand Up @@ -12730,6 +12748,19 @@ def err_acc_gang_reduction_numgangs_conflict
def err_reduction_op_mismatch
: Error<"OpenACC 'reduction' variable must have the same operator in all "
"nested constructs (%0 vs %1)">;
def err_acc_loop_variable_type
: Error<"loop variable of loop associated with an OpenACC 'loop' construct "
"must be of integer, pointer, or random-access-iterator type (is "
"%0)">;
def err_acc_loop_variable
: Error<"OpenACC 'loop' construct must have initialization clause in "
"canonical form ('var = init' or 'T var = init')">;
def err_acc_loop_terminating_condition
: Error<"OpenACC 'loop' construct must have a terminating condition">;
def err_acc_loop_not_monotonic
: Error<"OpenACC 'loop' variable must monotonically increase or decrease "
"('++', '--', or compound assignment)">;

// AMDGCN builtins diagnostics
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;
def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be 1, 2, or 4">;
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/OpenMPKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
#ifndef OPENMP_DOACROSS_MODIFIER
#define OPENMP_DOACROSS_MODIFIER(Name)
#endif
#ifndef OPENMP_ALLOCATE_MODIFIER
#define OPENMP_ALLOCATE_MODIFIER(Name)
#endif

// Static attributes for 'schedule' clause.
OPENMP_SCHEDULE_KIND(static)
Expand Down Expand Up @@ -214,6 +217,9 @@ OPENMP_GRAINSIZE_MODIFIER(strict)
// Modifiers for the 'num_tasks' clause.
OPENMP_NUMTASKS_MODIFIER(strict)

// Modifiers for 'allocate' clause.
OPENMP_ALLOCATE_MODIFIER(allocator)

// Modifiers for the 'doacross' clause.
OPENMP_DOACROSS_MODIFIER(source)
OPENMP_DOACROSS_MODIFIER(sink)
Expand Down Expand Up @@ -245,4 +251,5 @@ OPENMP_DOACROSS_MODIFIER(source_omp_cur_iteration)
#undef OPENMP_DEFAULTMAP_KIND
#undef OPENMP_DEFAULTMAP_MODIFIER
#undef OPENMP_DOACROSS_MODIFIER
#undef OPENMP_ALLOCATE_MODIFIER

7 changes: 7 additions & 0 deletions clang/include/clang/Basic/OpenMPKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,13 @@ enum OpenMPDoacrossClauseModifier {
OMPC_DOACROSS_unknown
};

/// OpenMP modifiers for 'allocate' clause.
enum OpenMPAllocateClauseModifier {
#define OPENMP_ALLOCATE_MODIFIER(Name) OMPC_ALLOCATE_##Name,
#include "clang/Basic/OpenMPKinds.def"
OMPC_ALLOCATE_unknown
};

/// Contains 'interop' data for 'append_args' and 'init' clauses.
class Expr;
struct OMPInteropInfo final {
Expand Down
Loading