22 changes: 14 additions & 8 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,19 +217,13 @@ 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);
Expand Down
13 changes: 13 additions & 0 deletions bolt/lib/Passes/SplitFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,12 @@ Error SplitFunctions::runOnFunctions(BinaryContext &BC) {
if (!opts::SplitFunctions)
return Error::success();

if (BC.IsLinuxKernel && BC.BOLTReserved.empty()) {
BC.errs() << "BOLT-ERROR: split functions require reserved space in the "
"Linux kernel binary\n";
exit(1);
}

// If split strategy is not CDSplit, then a second run of the pass is not
// needed after function reordering.
if (BC.HasFinalizedFunctionOrder &&
Expand Down Expand Up @@ -829,6 +835,13 @@ void SplitFunctions::splitFunction(BinaryFunction &BF, SplitStrategy &S) {
}
}
}

// Outlining blocks with dynamic branches is not supported yet.
if (BC.IsLinuxKernel) {
if (llvm::any_of(
*BB, [&](MCInst &Inst) { return BC.MIB->isDynamicBranch(Inst); }))
BB->setCanOutline(false);
}
}

BF.getLayout().updateLayoutIndices();
Expand Down
36 changes: 13 additions & 23 deletions bolt/lib/Profile/DataAggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -861,14 +861,17 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second,
return true;
}

bool DataAggregator::recordTrace(
BinaryFunction &BF, const LBREntry &FirstLBR, const LBREntry &SecondLBR,
uint64_t Count,
SmallVector<std::pair<uint64_t, uint64_t>, 16> &Branches) const {
std::optional<SmallVector<std::pair<uint64_t, uint64_t>, 16>>
DataAggregator::getFallthroughsInTrace(BinaryFunction &BF,
const LBREntry &FirstLBR,
const LBREntry &SecondLBR,
uint64_t Count) const {
SmallVector<std::pair<uint64_t, uint64_t>, 16> Branches;

BinaryContext &BC = BF.getBinaryContext();

if (!BF.isSimple())
return false;
return std::nullopt;

assert(BF.hasCFG() && "can only record traces in CFG state");

Expand All @@ -877,13 +880,13 @@ bool DataAggregator::recordTrace(
const uint64_t To = SecondLBR.From - BF.getAddress();

if (From > To)
return false;
return std::nullopt;

const BinaryBasicBlock *FromBB = BF.getBasicBlockContainingOffset(From);
const BinaryBasicBlock *ToBB = BF.getBasicBlockContainingOffset(To);

if (!FromBB || !ToBB)
return false;
return std::nullopt;

// Adjust FromBB if the first LBR is a return from the last instruction in
// the previous block (that instruction should be a call).
Expand All @@ -907,7 +910,7 @@ bool DataAggregator::recordTrace(
// within the same basic block, e.g. when two call instructions are in the
// same block. In this case we skip the processing.
if (FromBB == ToBB)
return true;
return Branches;

// Process blocks in the original layout order.
BinaryBasicBlock *BB = BF.getLayout().getBlock(FromBB->getIndex());
Expand All @@ -921,7 +924,7 @@ bool DataAggregator::recordTrace(
LLVM_DEBUG(dbgs() << "no fall-through for the trace:\n"
<< " " << FirstLBR << '\n'
<< " " << SecondLBR << '\n');
return false;
return std::nullopt;
}

const MCInst *Instr = BB->getLastNonPseudoInstr();
Expand All @@ -945,20 +948,7 @@ bool DataAggregator::recordTrace(
BI.Count += Count;
}

return true;
}

std::optional<SmallVector<std::pair<uint64_t, uint64_t>, 16>>
DataAggregator::getFallthroughsInTrace(BinaryFunction &BF,
const LBREntry &FirstLBR,
const LBREntry &SecondLBR,
uint64_t Count) const {
SmallVector<std::pair<uint64_t, uint64_t>, 16> Res;

if (!recordTrace(BF, FirstLBR, SecondLBR, Count, Res))
return std::nullopt;

return Res;
return Branches;
}

bool DataAggregator::recordEntry(BinaryFunction &BF, uint64_t To, bool Mispred,
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
274 changes: 149 additions & 125 deletions bolt/lib/Rewrite/LinuxKernelRewriter.cpp

Large diffs are not rendered by default.

82 changes: 44 additions & 38 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,35 @@ void RewriteInstance::discoverFileObjects() {

registerFragments();
FileSymbols.clear();

discoverBOLTReserved();
}

void RewriteInstance::discoverBOLTReserved() {
BinaryData *StartBD = BC->getBinaryDataByName(getBOLTReservedStart());
BinaryData *EndBD = BC->getBinaryDataByName(getBOLTReservedEnd());
if (!StartBD != !EndBD) {
BC->errs() << "BOLT-ERROR: one of the symbols is missing from the binary: "
<< getBOLTReservedStart() << ", " << getBOLTReservedEnd()
<< '\n';
exit(1);
}

if (!StartBD)
return;

if (StartBD->getAddress() >= EndBD->getAddress()) {
BC->errs() << "BOLT-ERROR: invalid reserved space boundaries\n";
exit(1);
}
BC->BOLTReserved = AddressRange(StartBD->getAddress(), EndBD->getAddress());
BC->outs() << "BOLT-INFO: using reserved space for allocating new sections\n";

PHDRTableOffset = 0;
PHDRTableAddress = 0;
NewTextSegmentAddress = 0;
NewTextSegmentOffset = 0;
NextAvailableAddress = BC->BOLTReserved.start();
}

Error RewriteInstance::discoverRtFiniAddress() {
Expand Down Expand Up @@ -3617,26 +3646,6 @@ void RewriteInstance::updateMetadata() {
void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) {
BC->deregisterUnusedSections();

// Check if the input has a space reserved for BOLT.
BinaryData *StartBD = BC->getBinaryDataByName(getBOLTReservedStart());
BinaryData *EndBD = BC->getBinaryDataByName(getBOLTReservedEnd());
if (!StartBD != !EndBD) {
BC->errs() << "BOLT-ERROR: one of the symbols is missing from the binary: "
<< getBOLTReservedStart() << ", " << getBOLTReservedEnd()
<< '\n';
exit(1);
}

if (StartBD) {
PHDRTableOffset = 0;
PHDRTableAddress = 0;
NewTextSegmentAddress = 0;
NewTextSegmentOffset = 0;
NextAvailableAddress = StartBD->getAddress();
BC->outs()
<< "BOLT-INFO: using reserved space for allocating new sections\n";
}

// If no new .eh_frame was written, remove relocated original .eh_frame.
BinarySection *RelocatedEHFrameSection =
getSection(".relocated" + getEHFrameSectionName());
Expand All @@ -3657,12 +3666,12 @@ void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) {
// Map the rest of the sections.
mapAllocatableSections(MapSection);

if (StartBD) {
const uint64_t ReservedSpace = EndBD->getAddress() - StartBD->getAddress();
const uint64_t AllocatedSize = NextAvailableAddress - StartBD->getAddress();
if (ReservedSpace < AllocatedSize) {
BC->errs() << "BOLT-ERROR: reserved space (" << ReservedSpace << " byte"
<< (ReservedSpace == 1 ? "" : "s")
if (!BC->BOLTReserved.empty()) {
const uint64_t AllocatedSize =
NextAvailableAddress - BC->BOLTReserved.start();
if (BC->BOLTReserved.size() < AllocatedSize) {
BC->errs() << "BOLT-ERROR: reserved space (" << BC->BOLTReserved.size()
<< " byte" << (BC->BOLTReserved.size() == 1 ? "" : "s")
<< ") is smaller than required for new allocations ("
<< AllocatedSize << " bytes)\n";
exit(1);
Expand Down Expand Up @@ -4047,6 +4056,7 @@ void RewriteInstance::patchELFPHDRTable() {
NewWritableSegmentSize = NextAvailableAddress - NewWritableSegmentAddress;
}

const uint64_t SavedPos = OS.tell();
OS.seek(PHDRTableOffset);

auto createNewTextPhdr = [&]() {
Expand Down Expand Up @@ -4151,6 +4161,8 @@ void RewriteInstance::patchELFPHDRTable() {
<< "BOLT-ERROR: could not find PT_GNU_STACK program header to modify\n";
exit(1);
}

OS.seek(SavedPos);
}

namespace {
Expand Down Expand Up @@ -5041,10 +5053,6 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
assert((DynSymSection || BC->IsStaticExecutable) &&
"dynamic symbol table expected");
if (DynSymSection) {
// Set pointer to the end of the section, so we can use pwrite to update
// the dynamic symbol table.
Out->os().seek(DynSymSection->sh_offset + DynSymSection->sh_size);

updateELFSymbolTable(
File,
/*IsDynSym=*/true,
Expand Down Expand Up @@ -5853,13 +5861,11 @@ void RewriteInstance::writeEHFrameHeader() {

NextAvailableAddress += EHFrameHdrSec.getOutputSize();

if (const BinaryData *ReservedEnd =
BC->getBinaryDataByName(getBOLTReservedEnd())) {
if (NextAvailableAddress > ReservedEnd->getAddress()) {
BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName()
<< " into reserved space\n";
exit(1);
}
if (!BC->BOLTReserved.empty() &&
(NextAvailableAddress > BC->BOLTReserved.end())) {
BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName()
<< " into reserved space\n";
exit(1);
}

// Merge new .eh_frame with the relocated original so that gdb can locate all
Expand Down Expand Up @@ -5893,7 +5899,7 @@ uint64_t RewriteInstance::getNewValueForSymbol(const StringRef Name) {

uint64_t RewriteInstance::getFileOffsetForAddress(uint64_t Address) const {
// Check if it's possibly part of the new segment.
if (Address >= NewTextSegmentAddress)
if (NewTextSegmentAddress && Address >= NewTextSegmentAddress)
return Address - NewTextSegmentAddress + NewTextSegmentOffset;

// Find an existing segment that matches the address.
Expand Down
40 changes: 40 additions & 0 deletions bolt/test/X86/linux-smp-locks.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# REQUIRES: system-linux

## Check that BOLT correctly parses and updates the Linux kernel .smp_locks
## section.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
# RUN: llvm-bolt %t.exe --print-normalized --keep-nops=0 --bolt-info=0 -o %t.out \
# RUN: |& FileCheck %s

## Check the output of BOLT with NOPs removed.

# RUN: llvm-bolt %t.out -o %t.out.1 --print-normalized |& FileCheck %s

# CHECK: BOLT-INFO: Linux kernel binary detected
# CHECK: BOLT-INFO: parsed 2 SMP lock entries

.text
.globl _start
.type _start, %function
_start:
nop
nop
.L0:
lock incl (%rdi)
# CHECK: lock {{.*}} SMPLock
.L1:
lock orb $0x40, 0x4(%rsi)
# CHECK: lock {{.*}} SMPLock
ret
.size _start, .-_start

.section .smp_locks,"a",@progbits
.long .L0 - .
.long .L1 - .

## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
29 changes: 23 additions & 6 deletions bolt/test/X86/linux-static-keys.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## Check that BOLT correctly updates the Linux kernel static keys jump table.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: link_fdata %s %t.o %t.fdata
# RUN: llvm-strip --strip-unneeded %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr

Expand All @@ -11,6 +13,12 @@
# RUN: llvm-bolt %t.exe --print-normalized -o %t.out --keep-nops=0 \
# RUN: --bolt-info=0 |& FileCheck %s

## Verify that profile is matched correctly.

# RUN: llvm-bolt %t.exe --print-normalized -o %t.out --keep-nops=0 \
# RUN: --bolt-info=0 --data %t.fdata |& \
# RUN: FileCheck --check-prefix=CHECK-FDATA %s

## Verify the bindings again on the rewritten binary with nops removed.

# RUN: llvm-bolt %t.out -o %t.out.1 --print-normalized |& FileCheck %s
Expand All @@ -25,15 +33,24 @@ _start:
# CHECK: Binary Function "_start"
nop
.L0:
jmp .L1
jmp L1
# CHECK: jit
# CHECK-SAME: # ID: 1 {{.*}} # Likely: 0 # InitValue: 1
nop
.L1:
L1:
.nops 5
jmp .L0
# CHECK: jit
# CHECK-SAME: # ID: 2 {{.*}} # Likely: 1 # InitValue: 1
.L2:

## Check that a branch profile associated with a NOP is handled properly when
## dynamic branch is created.

# FDATA: 1 _start #L1# 1 _start #L2# 3 42
# CHECK-FDATA: jit {{.*}} # ID: 2
# CHECK-FDATA-NEXT: jmp
# CHECK-FDATA-NEXT: Successors: {{.*}} (mispreds: 3, count: 42)
L2:
nop
.size _start, .-_start

Expand All @@ -51,11 +68,11 @@ foo:
__start___jump_table:

.long .L0 - . # Jump address
.long .L1 - . # Target address
.long L1 - . # Target address
.quad 1 # Key address

.long .L1 - . # Jump address
.long .L2 - . # Target address
.long L1 - . # Jump address
.long L2 - . # Target address
.quad 0 # Key address

.globl __stop___jump_table
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@
//===----------------------------------------------------------------------===//

#include "CastingThroughVoidCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "llvm/ADT/StringSet.h"

using namespace clang::ast_matchers;

Expand All @@ -27,7 +25,8 @@ void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) {
hasSourceExpression(
explicitCastExpr(
hasSourceExpression(
expr(hasType(qualType().bind("source_type")))),
expr(hasType(qualType(unless(pointsTo(voidType())))
.bind("source_type")))),
hasDestinationType(
qualType(pointsTo(voidType())).bind("void_type")))
.bind("cast"))),
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
4 changes: 4 additions & 0 deletions clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "../misc/StaticAssertCheck.h"
#include "../misc/ThrowByValueCatchByReferenceCheck.h"
#include "../performance/MoveConstructorInitCheck.h"
#include "../readability/EnumInitialValueCheck.h"
#include "../readability/UppercaseLiteralSuffixCheck.h"
#include "CommandProcessorCheck.h"
#include "DefaultOperatorNewAlignmentCheck.h"
Expand Down Expand Up @@ -299,6 +300,9 @@ class CERTModule : public ClangTidyModule {
"cert-flp37-c");
// FIO
CheckFactories.registerCheck<misc::NonCopyableObjectsCheck>("cert-fio38-c");
// INT
CheckFactories.registerCheck<readability::EnumInitialValueCheck>(
"cert-int09-c");
// MSC
CheckFactories.registerCheck<bugprone::UnsafeFunctionsCheck>(
"cert-msc24-c");
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
21 changes: 4 additions & 17 deletions clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,6 @@ AST_MATCHER(QualType, isLocalConstQualified) {
return Node.isLocalConstQualified();
}

AST_MATCHER(QualType, isTypeOfType) {
return isa<TypeOfType>(Node.getTypePtr());
}

AST_MATCHER(QualType, isTypeOfExprType) {
return isa<TypeOfExprType>(Node.getTypePtr());
}

struct CheckResult {
// Source range of the relevant `const` token in the definition being checked.
CharSourceRange ConstRange;
Expand Down Expand Up @@ -110,16 +102,11 @@ void ConstReturnTypeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
void ConstReturnTypeCheck::registerMatchers(MatchFinder *Finder) {
// Find all function definitions for which the return types are `const`
// qualified, ignoring decltype types.
auto NonLocalConstType =
qualType(unless(isLocalConstQualified()),
anyOf(decltypeType(), autoType(), isTypeOfType(),
isTypeOfExprType(), substTemplateTypeParmType()));
Finder->addMatcher(
functionDecl(
returns(allOf(isConstQualified(), unless(NonLocalConstType))),
anyOf(isDefinition(), cxxMethodDecl(isPure())),
// Overridden functions are not actionable.
unless(cxxMethodDecl(isOverride())))
functionDecl(returns(isLocalConstQualified()),
anyOf(isDefinition(), cxxMethodDecl(isPure())),
// Overridden functions are not actionable.
unless(cxxMethodDecl(isOverride())))
.bind("func"),
this);
}
Expand Down
99 changes: 55 additions & 44 deletions clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,12 @@ namespace {
/// void f() { E e1 = EV1; }
///
/// After:
/// enum class E { EV1, EV2 };
/// void f() { E e1 = E::EV1; }
/// enum class E { V1, V2 };
/// void f() { E e1 = E::V1; }
///
/// Note that the respective project code might not compile anymore
/// if it made use of the now-gone implicit conversion to int.
/// This is out of scope for this tweak.
///
/// TODO: In the above example, we could detect that the values
/// start with the enum name, and remove that prefix.

class ScopifyEnum : public Tweak {
const char *id() const final;
Expand All @@ -63,14 +60,13 @@ class ScopifyEnum : public Tweak {
std::function<tooling::Replacement(StringRef, StringRef, unsigned)>;
llvm::Error addClassKeywordToDeclarations();
llvm::Error scopifyEnumValues();
llvm::Error scopifyEnumValue(const EnumConstantDecl &CD, StringRef Prefix);
llvm::Error scopifyEnumValue(const EnumConstantDecl &CD, StringRef EnumName,
bool StripPrefix);
llvm::Expected<StringRef> getContentForFile(StringRef FilePath);
unsigned getOffsetFromPosition(const Position &Pos, StringRef Content) const;
llvm::Error addReplacementForReference(const ReferencesResult::Reference &Ref,
const MakeReplacement &GetReplacement);
llvm::Error addReplacement(StringRef FilePath, StringRef Content,
const tooling::Replacement &Replacement);
Position getPosition(const Decl &D) const;

const EnumDecl *D = nullptr;
const Selection *S = nullptr;
Expand Down Expand Up @@ -109,7 +105,8 @@ Expected<Tweak::Effect> ScopifyEnum::apply(const Selection &Inputs) {

llvm::Error ScopifyEnum::addClassKeywordToDeclarations() {
for (const auto &Ref :
findReferences(*S->AST, getPosition(*D), 0, S->Index, false)
findReferences(*S->AST, sourceLocToPosition(*SM, D->getBeginLoc()), 0,
S->Index, false)
.References) {
if (!(Ref.Attributes & ReferencesResult::Declaration))
continue;
Expand All @@ -125,25 +122,46 @@ llvm::Error ScopifyEnum::addClassKeywordToDeclarations() {
}

llvm::Error ScopifyEnum::scopifyEnumValues() {
std::string PrefixToInsert(D->getName());
PrefixToInsert += "::";
for (auto E : D->enumerators()) {
if (auto Err = scopifyEnumValue(*E, PrefixToInsert))
StringRef EnumName(D->getName());
bool StripPrefix = true;
for (const EnumConstantDecl *E : D->enumerators()) {
if (!E->getName().starts_with(EnumName)) {
StripPrefix = false;
break;
}
}
for (const EnumConstantDecl *E : D->enumerators()) {
if (auto Err = scopifyEnumValue(*E, EnumName, StripPrefix))
return Err;
}
return llvm::Error::success();
}

llvm::Error ScopifyEnum::scopifyEnumValue(const EnumConstantDecl &CD,
StringRef Prefix) {
StringRef EnumName,
bool StripPrefix) {
for (const auto &Ref :
findReferences(*S->AST, getPosition(CD), 0, S->Index, false)
findReferences(*S->AST, sourceLocToPosition(*SM, CD.getBeginLoc()), 0,
S->Index, false)
.References) {
if (Ref.Attributes & ReferencesResult::Declaration)
if (Ref.Attributes & ReferencesResult::Declaration) {
if (StripPrefix) {
const auto MakeReplacement = [&EnumName](StringRef FilePath,
StringRef Content,
unsigned Offset) {
unsigned Length = EnumName.size();
if (Content[Offset + Length] == '_')
++Length;
return tooling::Replacement(FilePath, Offset, Length, {});
};
if (auto Err = addReplacementForReference(Ref, MakeReplacement))
return Err;
}
continue;
}

const auto MakeReplacement = [&Prefix](StringRef FilePath,
StringRef Content, unsigned Offset) {
const auto MakeReplacement = [&](StringRef FilePath, StringRef Content,
unsigned Offset) {
const auto IsAlreadyScoped = [Content, Offset] {
if (Offset < 2)
return false;
Expand All @@ -164,9 +182,18 @@ llvm::Error ScopifyEnum::scopifyEnumValue(const EnumConstantDecl &CD,
}
return false;
};
return IsAlreadyScoped()
? tooling::Replacement()
: tooling::Replacement(FilePath, Offset, 0, Prefix);
if (StripPrefix) {
const int ExtraLength =
Content[Offset + EnumName.size()] == '_' ? 1 : 0;
if (IsAlreadyScoped())
return tooling::Replacement(FilePath, Offset,
EnumName.size() + ExtraLength, {});
return tooling::Replacement(FilePath, Offset + EnumName.size(),
ExtraLength, "::");
}
return IsAlreadyScoped() ? tooling::Replacement()
: tooling::Replacement(FilePath, Offset, 0,
EnumName.str() + "::");
};
if (auto Err = addReplacementForReference(Ref, MakeReplacement))
return Err;
Expand All @@ -187,27 +214,19 @@ llvm::Expected<StringRef> ScopifyEnum::getContentForFile(StringRef FilePath) {
return Content;
}

unsigned int ScopifyEnum::getOffsetFromPosition(const Position &Pos,
StringRef Content) const {
unsigned int Offset = 0;

for (std::size_t LinesRemaining = Pos.line;
Offset < Content.size() && LinesRemaining;) {
if (Content[Offset++] == '\n')
--LinesRemaining;
}
return Offset + Pos.character;
}

llvm::Error
ScopifyEnum::addReplacementForReference(const ReferencesResult::Reference &Ref,
const MakeReplacement &GetReplacement) {
StringRef FilePath = Ref.Loc.uri.file();
auto Content = getContentForFile(FilePath);
llvm::Expected<StringRef> Content = getContentForFile(FilePath);
if (!Content)
return Content.takeError();
unsigned Offset = getOffsetFromPosition(Ref.Loc.range.start, *Content);
tooling::Replacement Replacement = GetReplacement(FilePath, *Content, Offset);
llvm::Expected<size_t> Offset =
positionToOffset(*Content, Ref.Loc.range.start);
if (!Offset)
return Offset.takeError();
tooling::Replacement Replacement =
GetReplacement(FilePath, *Content, *Offset);
if (Replacement.isApplicable())
return addReplacement(FilePath, *Content, Replacement);
return llvm::Error::success();
Expand All @@ -223,13 +242,5 @@ ScopifyEnum::addReplacement(StringRef FilePath, StringRef Content,
return llvm::Error::success();
}

Position ScopifyEnum::getPosition(const Decl &D) const {
const SourceLocation Loc = D.getLocation();
Position Pos;
Pos.line = SM->getSpellingLineNumber(Loc) - 1;
Pos.character = SM->getSpellingColumnNumber(Loc) - 1;
return Pos;
}

} // namespace
} // namespace clang::clangd
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# RUN: clangd -input-style=delimited -sync -input-mirror-file %t < %s
# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t
#
# RUN: clangd -lit-test -input-mirror-file %t < %s
# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t
#
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
---
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
# RUN: clangd -input-style=delimited -sync -input-mirror-file %t < %s
# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t
#
# RUN: clangd -lit-test -input-mirror-file %t < %s
# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t
#
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
---
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
114 changes: 57 additions & 57 deletions clang-tools-extra/clangd/test/hover.test
Original file line number Diff line number Diff line change
@@ -1,57 +1,57 @@
# RUN: clangd -lit-test < %s | FileCheck %s
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
---
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"void foo(); int main() { foo(); }\n"}}}
---
{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":27}}}
# CHECK: "id": 1,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "contents": {
# CHECK-NEXT: "kind": "plaintext",
# CHECK-NEXT: "value": "function foo\n\n→ void\n\nvoid foo()"
# CHECK-NEXT: },
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
# CHECK-NEXT: "character": 28,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: },
# CHECK-NEXT: "start": {
# CHECK-NEXT: "character": 25,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT:}
---
{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":10}}}
# CHECK: "id": 1,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": null
---
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main2.cpp","languageId":"cpp","version":1,"text":"enum foo{}; int main() { foo f; }\n"}}}
---
{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main2.cpp"},"position":{"line":0,"character":27}}}
# CHECK: "id": 1,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "contents": {
# CHECK-NEXT: "kind": "plaintext",
# CHECK-NEXT: "value": "enum foo\n\nenum foo {}"
# CHECK-NEXT: },
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
# CHECK-NEXT: "character": 28,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: },
# CHECK-NEXT: "start": {
# CHECK-NEXT: "character": 25,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT:}
---
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
# RUN: clangd -lit-test < %s | FileCheck %s
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
---
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"void foo(); int main() { foo(); }\n"}}}
---
{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":27}}}
# CHECK: "id": 1,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "contents": {
# CHECK-NEXT: "kind": "plaintext",
# CHECK-NEXT: "value": "function foo\n\n→ void\n\nvoid foo()"
# CHECK-NEXT: },
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
# CHECK-NEXT: "character": 28,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: },
# CHECK-NEXT: "start": {
# CHECK-NEXT: "character": 25,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT:}
---
{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":10}}}
# CHECK: "id": 1,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": null
---
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main2.cpp","languageId":"cpp","version":1,"text":"enum foo{}; int main() { foo f; }\n"}}}
---
{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main2.cpp"},"position":{"line":0,"character":27}}}
# CHECK: "id": 1,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "contents": {
# CHECK-NEXT: "kind": "plaintext",
# CHECK-NEXT: "value": "enum foo\n\nenum foo {}"
# CHECK-NEXT: },
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
# CHECK-NEXT: "character": 28,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: },
# CHECK-NEXT: "start": {
# CHECK-NEXT: "character": 25,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT:}
---
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
26 changes: 13 additions & 13 deletions clang-tools-extra/clangd/test/spaces-in-delimited-input.test
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# RUN: clangd -input-style=delimited -sync < %s 2>&1 | FileCheck %s
# RUN: clangd -lit-test -sync < %s 2>&1 | FileCheck %s
#
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
---
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
# CHECK-NOT: JSON parse error
# RUN: clangd -input-style=delimited -sync < %s 2>&1 | FileCheck %s
# RUN: clangd -lit-test -sync < %s 2>&1 | FileCheck %s
#
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}

---

{"jsonrpc":"2.0","id":3,"method":"shutdown"}

---

{"jsonrpc":"2.0","method":"exit"}
# CHECK-NOT: JSON parse error
8 changes: 4 additions & 4 deletions clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
EXPECT_DECLS("MemberExpr", "void foo()");

// Similar to above but base expression involves a function call.
Code = R"cpp(
Expand All @@ -872,7 +872,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
EXPECT_DECLS("MemberExpr", "void foo()");

// Similar to above but uses a function pointer.
Code = R"cpp(
Expand All @@ -891,7 +891,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
EXPECT_DECLS("MemberExpr", "void foo()");

// Base expression involves a member access into this.
Code = R"cpp(
Expand Down Expand Up @@ -962,7 +962,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
void Foo() { this->[[find]](); }
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()");
EXPECT_DECLS("MemberExpr", "void find()");
}

TEST_F(TargetDeclTest, DependentTypes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ sizeof...($TemplateParameter[[Elements]]);
struct $Class_def[[Foo]] {
int $Field_decl[[Waldo]];
void $Method_def[[bar]]() {
$Class[[Foo]]().$Field_dependentName[[Waldo]];
$Class[[Foo]]().$Field[[Waldo]];
}
template $Bracket[[<]]typename $TemplateParameter_def[[U]]$Bracket[[>]]
void $Method_def[[bar1]]() {
Expand Down
66 changes: 61 additions & 5 deletions clang-tools-extra/clangd/unittests/tweaks/ScopifyEnumTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ enum ^E;
)cpp");
}

TEST_F(ScopifyEnumTest, ApplyTest) {
TEST_F(ScopifyEnumTest, ApplyTestWithPrefix) {
std::string Original = R"cpp(
enum ^E { EV1, EV2, EV3 };
enum E;
Expand All @@ -39,13 +39,69 @@ E func(E in)
}
)cpp";
std::string Expected = R"cpp(
enum class E { EV1, EV2, EV3 };
enum class E { V1, V2, V3 };
enum class E;
E func(E in)
{
E out = E::EV1;
if (in == E::EV2)
out = E::EV3;
E out = E::V1;
if (in == E::V2)
out = E::V3;
return out;
}
)cpp";
FileName = "Test.cpp";
SCOPED_TRACE(Original);
EXPECT_EQ(apply(Original), Expected);
}

TEST_F(ScopifyEnumTest, ApplyTestWithPrefixAndUnderscore) {
std::string Original = R"cpp(
enum ^E { E_V1, E_V2, E_V3 };
enum E;
E func(E in)
{
E out = E_V1;
if (in == E_V2)
out = E::E_V3;
return out;
}
)cpp";
std::string Expected = R"cpp(
enum class E { V1, V2, V3 };
enum class E;
E func(E in)
{
E out = E::V1;
if (in == E::V2)
out = E::V3;
return out;
}
)cpp";
FileName = "Test.cpp";
SCOPED_TRACE(Original);
EXPECT_EQ(apply(Original), Expected);
}

TEST_F(ScopifyEnumTest, ApplyTestWithoutPrefix) {
std::string Original = R"cpp(
enum ^E { V1, V2, V3 };
enum E;
E func(E in)
{
E out = V1;
if (in == V2)
out = E::V3;
return out;
}
)cpp";
std::string Expected = R"cpp(
enum class E { V1, V2, V3 };
enum class E;
E func(E in)
{
E out = E::V1;
if (in == E::V2)
out = E::V3;
return out;
}
)cpp";
Expand Down
19 changes: 18 additions & 1 deletion clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ Code completion
Code actions
^^^^^^^^^^^^

- The tweak for turning unscoped into scoped enums now removes redundant prefixes
from the enum values.

Signature help
^^^^^^^^^^^^^^

Expand Down Expand Up @@ -166,13 +169,22 @@ New checks
New check aliases
^^^^^^^^^^^^^^^^^

- New alias :doc:`cert-int09-c <clang-tidy/checks/cert/int09-c>` to
:doc:`readability-enum-initial-value <clang-tidy/checks/readability/enum-initial-value>`
was added.

Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^

- Improved :doc:`bugprone-assert-side-effect
<clang-tidy/checks/bugprone/assert-side-effect>` check by detecting side
effect from calling a method with non-const reference parameters.

- Improved :doc:`bugprone-casting-through-void
<clang-tidy/checks/bugprone/casting-through-void>` check by ignoring casts
where source is already a ``void``` pointer, making middle ``void`` pointer
casts bug-free.

- Improved :doc:`bugprone-forwarding-reference-overload
<clang-tidy/checks/bugprone/forwarding-reference-overload>`
check to ignore deleted constructors which won't hide other overloads.
Expand Down Expand Up @@ -261,7 +273,8 @@ Changes in existing checks

- Improved :doc:`misc-const-correctness
<clang-tidy/checks/misc/const-correctness>` check by avoiding infinite recursion
for recursive forwarding reference.
for recursive functions with forwarding reference parameters and reference
variables which refer to themselves.

- Improved :doc:`misc-definitions-in-headers
<clang-tidy/checks/misc/definitions-in-headers>` check by replacing the local
Expand Down Expand Up @@ -312,6 +325,10 @@ Changes in existing checks
<clang-tidy/checks/readability/avoid-return-with-void-value>` check by adding
fix-its.

- Improved :doc:`readability-const-return-type
<clang-tidy/checks/readability/const-return-type>` check to eliminate false
positives when returning types with const not at the top level.

- Improved :doc:`readability-duplicate-include
<clang-tidy/checks/readability/duplicate-include>` check by excluding include
directives that form the filename using macro.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ just the individual thread. Use any signal except ``SIGTERM``.
This check corresponds to the CERT C Coding Standard rule
`POS44-C. Do not use signals to terminate threads
<https://wiki.sei.cmu.edu/confluence/display/c/POS44-C.+Do+not+use+signals+to+terminate+threads>`_.

`cert-pos44-c` redirects here as an alias of this check.
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ completely before it is used.
It is also recommended to surround macro arguments in the replacement list
with parentheses. This ensures that the argument value is calculated
properly.

This check corresponds to the CERT C Coding Standard rule
`PRE20-C. Macro replacement lists should be parenthesized.
<https://wiki.sei.cmu.edu/confluence/display/c/PRE02-C.+Macro+replacement+lists+should+be+parenthesized>`_
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ This check is also related to and partially overlaps the CERT C++ Coding Standar
and
`EXP62-CPP. Do not access the bits of an object representation that are not part of the object's value representation
<https://wiki.sei.cmu.edu/confluence/display/cplusplus/EXP62-CPP.+Do+not+access+the+bits+of+an+object+representation+that+are+not+part+of+the+object%27s+value+representation>`_

`cert-exp42-c` redirects here as an alias of this check.
10 changes: 10 additions & 0 deletions clang-tools-extra/docs/clang-tidy/checks/cert/int09-c.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.. title:: clang-tidy - cert-int09-c
.. meta::
:http-equiv=refresh: 5;URL=../readability/enum-initial-value.html

cert-int09-c
============

The `cert-int09-c` check is an alias, please see
:doc:`readability-enum-initial-value <../readability/enum-initial-value>` for
more information.
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ be acted upon and the effect is as if it was an asynchronous cancellation.
This check corresponds to the CERT C Coding Standard rule
`POS47-C. Do not use threads that can be canceled asynchronously
<https://wiki.sei.cmu.edu/confluence/display/c/POS47-C.+Do+not+use+threads+that+can+be+canceled+asynchronously>`_.

`cert-pos47-c` redirects here as an alias of this check.
7 changes: 5 additions & 2 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ Clang-Tidy Checks
:doc:`bugprone-posix-return <bugprone/posix-return>`, "Yes"
:doc:`bugprone-redundant-branch-condition <bugprone/redundant-branch-condition>`, "Yes"
:doc:`bugprone-reserved-identifier <bugprone/reserved-identifier>`, "Yes"
:doc:`bugprone-return-const-ref-from-parameter <bugprone/return-const-ref-from-parameter>`
:doc:`bugprone-return-const-ref-from-parameter <bugprone/return-const-ref-from-parameter>`,
:doc:`bugprone-shared-ptr-array-mismatch <bugprone/shared-ptr-array-mismatch>`, "Yes"
:doc:`bugprone-signal-handler <bugprone/signal-handler>`,
:doc:`bugprone-signed-char-misuse <bugprone/signed-char-misuse>`,
Expand Down Expand Up @@ -395,8 +395,10 @@ Clang-Tidy Checks
:doc:`readability-use-std-min-max <readability/use-std-min-max>`, "Yes"
:doc:`zircon-temporary-objects <zircon/temporary-objects>`,

Check aliases
-------------

.. csv-table:: Aliases..
.. csv-table::
:header: "Name", "Redirect", "Offers fixes"

:doc:`bugprone-narrowing-conversions <bugprone/narrowing-conversions>`, :doc:`cppcoreguidelines-narrowing-conversions <cppcoreguidelines/narrowing-conversions>`,
Expand All @@ -413,6 +415,7 @@ Clang-Tidy Checks
:doc:`cert-exp42-c <cert/exp42-c>`, :doc:`bugprone-suspicious-memory-comparison <bugprone/suspicious-memory-comparison>`,
:doc:`cert-fio38-c <cert/fio38-c>`, :doc:`misc-non-copyable-objects <misc/non-copyable-objects>`,
:doc:`cert-flp37-c <cert/flp37-c>`, :doc:`bugprone-suspicious-memory-comparison <bugprone/suspicious-memory-comparison>`,
:doc:`cert-int09-c <cert/int09-c>`, :doc:`readability-enum-initial-value <readability/enum-initial-value>`, "Yes"
:doc:`cert-msc24-c <cert/msc24-c>`, :doc:`bugprone-unsafe-functions <bugprone/unsafe-functions>`,
:doc:`cert-msc30-c <cert/msc30-c>`, :doc:`cert-msc50-cpp <cert/msc50-cpp>`,
:doc:`cert-msc32-c <cert/msc32-c>`, :doc:`cert-msc51-cpp <cert/msc51-cpp>`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
misc-throw-by-value-catch-by-reference
======================================

`cert-err09-cpp` redirects here as an alias for this check.
`cert-err61-cpp` redirects here as an alias for this check.
`cert-err09-cpp` and `cert-err61-cpp` redirect here as aliases of this check.

Finds violations of the rule "Throw by value, catch by reference" presented for
example in "C++ Coding Standards" by H. Sutter and A. Alexandrescu, as well as
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 @@ -6,70 +6,83 @@ readability-enum-initial-value
Enforces consistent style for enumerators' initialization, covering three
styles: none, first only, or all initialized explicitly.

When adding new enumerations, inconsistent initial value will cause potential
enumeration value conflicts.
An inconsistent style and strictness to defining the initializing value of
enumerators may cause issues if the enumeration is extended with new
enumerators that obtain their integer representation implicitly.

In an enumeration, the following three cases are accepted.
1. none of enumerators are explicit initialized.
2. the first enumerator is explicit initialized.
3. all of enumerators are explicit initialized.
The following three cases are accepted:

#. **No** enumerators are explicit initialized.
#. Exactly **the first** enumerator is explicit initialized.
#. **All** enumerators are explicit initialized.

.. code-block:: c++

// valid, none of enumerators are initialized.
enum A {
e0,
e1,
e2,
enum A { // (1) Valid, none of enumerators are initialized.
a0,
a1,
a2,
};

// valid, the first enumerator is initialized.
enum A {
e0 = 0,
e1,
e2,
enum B { // (2) Valid, the first enumerator is initialized.
b0 = 0,
b1,
b2,
};

// valid, all of enumerators are initialized.
enum A {
e0 = 0,
e1 = 1,
e2 = 2,
enum C { // (3) Valid, all of enumerators are initialized.
c0 = 0,
c1 = 1,
c2 = 2,
};

// invalid, e1 is not explicit initialized.
enum A {
enum D { // Invalid, d1 is not explicitly initialized!
d0 = 0,
d1,
d2 = 2,
};

enum E { // Invalid, e1, e3, and e5 are not explicitly initialized.
e0 = 0,
e1,
e2 = 2,
e3, // Dangerous, as the numeric values of e3 and e5 are both 3, and this is not explicitly visible in the code!
e4 = 2,
e5,
};

This check corresponds to the CERT C Coding Standard recommendation `INT09-C. Ensure enumeration constants map to unique values
<https://wiki.sei.cmu.edu/confluence/display/c/INT09-C.+Ensure+enumeration+constants+map+to+unique+values>`_.

`cert-int09-c` redirects here as an alias of this check.

Options
-------

.. option:: AllowExplicitZeroFirstInitialValue

If set to `false`, the first enumerator must not be explicitly initialized.
See examples below. Default is `true`.
If set to `false`, the first enumerator must not be explicitly initialized to
a literal ``0``.
Default is `true`.

.. code-block:: c++

enum A {
e0 = 0, // not allowed if AllowExplicitZeroFirstInitialValue is false
e1,
e2,
enum F {
f0 = 0, // Not allowed if AllowExplicitZeroFirstInitialValue is false.
f1,
f2,
};


.. option:: AllowExplicitSequentialInitialValues

If set to `false`, sequential initializations are not allowed.
See examples below. Default is `true`.
If set to `false`, explicit initialization to sequential values are not
allowed.
Default is `true`.

.. code-block:: c++

enum A {
e0 = 1, // not allowed if AllowExplicitSequentialInitialValues is false
e1 = 2,
e2 = 3,
};
enum G {
g0 = 1, // Not allowed if AllowExplicitSequentialInitialValues is false.
g1 = 2,
g2 = 3,
45 changes: 21 additions & 24 deletions clang-tools-extra/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,33 +67,30 @@ foreach(dep ${LLVM_UTILS_DEPS})
endif()
endforeach()

if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
if (NOT WIN32 OR NOT LLVM_LINK_LLVM_DYLIB)
llvm_add_library(
CTTestTidyModule
MODULE clang-tidy/CTTestTidyModule.cpp
PLUGIN_TOOL clang-tidy
DEPENDS clang-tidy-headers)
endif()
if (NOT WIN32 OR NOT LLVM_LINK_LLVM_DYLIB)
llvm_add_library(
CTTestTidyModule
MODULE clang-tidy/CTTestTidyModule.cpp
PLUGIN_TOOL clang-tidy)
endif()

if(CLANG_BUILT_STANDALONE)
# LLVMHello library is needed below
if (EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Transforms/Hello
AND NOT TARGET LLVMHello)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/lib/Transforms/Hello
lib/Transforms/Hello)
endif()
if(CLANG_BUILT_STANDALONE)
# LLVMHello library is needed below
if (EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Transforms/Hello
AND NOT TARGET LLVMHello)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/lib/Transforms/Hello
lib/Transforms/Hello)
endif()
endif()

if(TARGET CTTestTidyModule)
list(APPEND CLANG_TOOLS_TEST_DEPS CTTestTidyModule LLVMHello)
target_include_directories(CTTestTidyModule PUBLIC BEFORE "${CLANG_TOOLS_SOURCE_DIR}")
if(CLANG_PLUGIN_SUPPORT AND (WIN32 OR CYGWIN))
set(LLVM_LINK_COMPONENTS
Support
)
endif()
endif()
if(TARGET CTTestTidyModule)
list(APPEND CLANG_TOOLS_TEST_DEPS CTTestTidyModule LLVMHello)
target_include_directories(CTTestTidyModule PUBLIC BEFORE "${CLANG_TOOLS_SOURCE_DIR}")
if(CLANG_PLUGIN_SUPPORT AND (WIN32 OR CYGWIN))
set(LLVM_LINK_COMPONENTS
Support
)
endif()
endif()

add_lit_testsuite(check-clang-extra "Running clang-tools-extra/test"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,10 @@ void bit_cast() {
__builtin_bit_cast(int *, static_cast<void *>(&d));
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void]
}

namespace PR87069 {
void castconstVoidToVoid() {
const void* ptr = nullptr;
int* numberPtr = static_cast<int*>(const_cast<void*>(ptr));
}
}
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 @@ -309,6 +309,8 @@ struct HeapArray { // Ok, since destruc

HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok
other._data = nullptr; // Ok
// CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t'
// FIXME: This warning is emitted because an ImplicitCastExpr for the NullToPointer conversion isn't created for dependent types.
other.size = 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ template <class T>
struct Template {
Template() = default;
Template(const Template &Other) : Field(Other.Field) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
// CHECK-FIXES: Template(const Template &Other) = default;
Template &operator=(const Template &Other);
void foo(const T &t);
int Field;
Expand All @@ -269,8 +271,12 @@ Template<T> &Template<T>::operator=(const Template<T> &Other) {
Field = Other.Field;
return *this;
}
// CHECK-MESSAGES: :[[@LINE-4]]:27: warning: use '= default'
// CHECK-FIXES: Template<T> &Template<T>::operator=(const Template<T> &Other) = default;

Template<int> T1;


// Dependent types.
template <class T>
struct DT1 {
Expand All @@ -284,6 +290,9 @@ DT1<T> &DT1<T>::operator=(const DT1<T> &Other) {
Field = Other.Field;
return *this;
}
// CHECK-MESSAGES: :[[@LINE-4]]:17: warning: use '= default'
// CHECK-FIXES: DT1<T> &DT1<T>::operator=(const DT1<T> &Other) = default;

DT1<int> Dt1;

template <class T>
Expand All @@ -303,6 +312,9 @@ DT2<T> &DT2<T>::operator=(const DT2<T> &Other) {
struct T {
typedef int TT;
};
// CHECK-MESSAGES: :[[@LINE-8]]:17: warning: use '= default'
// CHECK-FIXES: DT2<T> &DT2<T>::operator=(const DT2<T> &Other) = default;

DT2<T> Dt2;

// Default arguments.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#ifndef READABILITY_DUPLICATE_INCLUDE_H
#define READABILITY_DUPLICATE_INCLUDE_H

extern int g;
#include "duplicate-include2.h"
extern int h;
#include "duplicate-include2.h"
extern int i;
// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: duplicate include
// CHECK-FIXES: {{^extern int g;$}}
// CHECK-FIXES-NEXT: {{^#include "duplicate-include2.h"$}}
// CHECK-FIXES-NEXT: {{^extern int h;$}}
// CHECK-FIXES-NEXT: {{^extern int i;$}}

#endif
#ifndef READABILITY_DUPLICATE_INCLUDE_H
#define READABILITY_DUPLICATE_INCLUDE_H

extern int g;
#include "duplicate-include2.h"
extern int h;
#include "duplicate-include2.h"
extern int i;
// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: duplicate include
// CHECK-FIXES: {{^extern int g;$}}
// CHECK-FIXES-NEXT: {{^#include "duplicate-include2.h"$}}
// CHECK-FIXES-NEXT: {{^extern int h;$}}
// CHECK-FIXES-NEXT: {{^extern int i;$}}

#endif
Original file line number Diff line number Diff line change
@@ -1 +1 @@
// This file is intentionally empty.
// This file is intentionally empty.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
// This file is intentionally empty.
// This file is intentionally empty.
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,9 @@ CREATE_FUNCTION();

using ty = const int;
ty p21() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty' (aka 'const int') is

typedef const int ty2;
ty2 p22() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty2' (aka 'const int') i

// Declaration uses a macro, while definition doesn't. In this case, we won't
// fix the declaration, and will instead issue a warning.
Expand Down Expand Up @@ -249,7 +247,6 @@ auto p27() -> int const { return 3; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu

std::add_const<int>::type p28() { return 3; }
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'std::add_const<int>::typ

// p29, p30 are based on
// llvm/projects/test-suite/SingleSource/Benchmarks/Misc-C++-EH/spirit.cpp:
Expand Down Expand Up @@ -355,3 +352,20 @@ struct p41 {
// CHECK-FIXES: T foo() const { return 2; }
};
template struct p41<int>;

namespace PR73270 {
template<typename K, typename V>
struct Pair {
using first_type = const K;
using second_type = V;
};

template<typename PairType>
typename PairType::first_type getFirst() {
return {};
}

void test() {
getFirst<Pair<int, int>>();
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
// RUN: %check_clang_tidy %s readability-else-after-return %t -- -- -std=c++17

// Constexpr if is an exception to the rule, we cannot remove the else.
void f() {
if (sizeof(int) > 4)
return;
else
return;
// CHECK-MESSAGES: [[@LINE-2]]:3: warning: do not use 'else' after 'return'

if constexpr (sizeof(int) > 4)
return;
else
return;

if constexpr (sizeof(int) > 4)
return;
else if constexpr (sizeof(long) > 4)
return;
else
return;
}
// RUN: %check_clang_tidy %s readability-else-after-return %t -- -- -std=c++17

// Constexpr if is an exception to the rule, we cannot remove the else.
void f() {
if (sizeof(int) > 4)
return;
else
return;
// CHECK-MESSAGES: [[@LINE-2]]:3: warning: do not use 'else' after 'return'

if constexpr (sizeof(int) > 4)
return;
else
return;

if constexpr (sizeof(int) > 4)
return;
else if constexpr (sizeof(long) > 4)
return;
else
return;
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,5 @@
// RUN: clang-tidy --checks="-*,readability-identifier-naming" --dump-config %S/Inputs/config-files/- -- | grep "readability-identifier-naming\." | sort --check

// Dumped config does not overflow for unsigned options
// RUN: clang-tidy --dump-config \
// RUN: --checks="-*,misc-throw-by-value-catch-by-reference" \
// RUN: -- | grep -v -q "misc-throw-by-value-catch-by-reference.MaxSize: '-1'"

// RUN: clang-tidy --dump-config %S/Inputs/config-files/5/- \
// RUN: -- | grep -q "misc-throw-by-value-catch-by-reference.MaxSize: '1152921504606846976'"
// RUN: clang-tidy --dump-config %S/Inputs/config-files/5/- -- | FileCheck %s -check-prefix=CHECK-OVERFLOW
// CHECK-OVERFLOW: misc-throw-by-value-catch-by-reference.MaxSize: '1152921504606846976'
2 changes: 1 addition & 1 deletion clang-tools-extra/test/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ config.python_executable = "@Python3_EXECUTABLE@"
config.target_triple = "@LLVM_TARGET_TRIPLE@"
config.host_triple = "@LLVM_HOST_TRIPLE@"
config.clang_tidy_staticanalyzer = @CLANG_TIDY_ENABLE_STATIC_ANALYZER@
config.has_plugins = @CLANG_PLUGIN_SUPPORT@ & ~@LLVM_INSTALL_TOOLCHAIN_ONLY@
config.has_plugins = @CLANG_PLUGIN_SUPPORT@
# Support substitution of the tools and libs dirs with user parameters. This is
# used when we can't determine the tool dir at configuration time.
config.llvm_tools_dir = lit_config.substitute("@LLVM_TOOLS_DIR@")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// module.modulemap
module Level1A {
header "Level1A.h"
export *
}
module HasError {
header "HasError.h"
export *
}
// module.modulemap

module Level1A {
header "Level1A.h"
export *
}
module HasError {
header "HasError.h"
export *
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// module.modulemap
module Level1A {
header "Level1A.h"
export *
}
module Missing {
header "Missing.h"
export *
}
// module.modulemap

module Level1A {
header "Level1A.h"
export *
}
module Missing {
header "Missing.h"
export *
}
36 changes: 18 additions & 18 deletions clang-tools-extra/test/pp-trace/Inputs/module.modulemap
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// module.modulemap
module Level1A {
header "Level1A.h"
export *
}
module Level1B {
header "Level1B.h"
export *
module Level2B {
header "Level2B.h"
export *
}
}
module Level2A {
header "Level2A.h"
export *
}
// module.modulemap

module Level1A {
header "Level1A.h"
export *
}
module Level1B {
header "Level1B.h"
export *
module Level2B {
header "Level2B.h"
export *
}
}
module Level2A {
header "Level2A.h"
export *
}
4 changes: 2 additions & 2 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -935,8 +935,8 @@ 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 AlignCaseColons`` Whether aligned case labels are aligned on the colon, or on the tokens
after the colon.

.. code-block:: c++

Expand Down
4 changes: 2 additions & 2 deletions clang/docs/Multilib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,9 @@ For a more comprehensive example see
- Dir: thumb/v6-m
# List of one or more normalized command line options, as generated by Clang
# from the command line options or from Mappings below.
# Here, if the flags are a superset of {target=thumbv6m-none-unknown-eabi}
# Here, if the flags are a superset of {target=thumbv6m-unknown-none-eabi}
# then this multilib variant will be considered a match.
Flags: [--target=thumbv6m-none-unknown-eabi]
Flags: [--target=thumbv6m-unknown-none-eabi]
# Similarly, a multilib variant targeting Arm v7-M with an FPU (floating
# point unit).
Expand Down
77 changes: 73 additions & 4 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ C++ Specific Potentially Breaking Changes
- Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template<class T> void T();``.
This error can be disabled via `-Wno-strict-primary-template-shadow` for compatibility with previous versions of clang.

- The behavior controlled by the `-frelaxed-template-template-args` flag is now
on by default, and the flag is deprecated. Until the flag is finally removed,
it's negative spelling can be used to obtain compatibility with previous
versions of clang.

- Clang now rejects pointer to member from parenthesized expression in unevaluated context such as ``decltype(&(foo::bar))``. (#GH40906).

ABI Changes in This Version
---------------------------
- Fixed Microsoft name mangling of implicitly defined variables used for thread
Expand Down Expand Up @@ -85,6 +92,25 @@ Clang Frontend Potentially Breaking Changes
of ``-Wno-gnu-binary-literal`` will no longer silence this pedantic warning,
which may break existing uses with ``-Werror``.

- The normalization of 3 element target triples where ``-none-`` is the middle
element has changed. For example, ``armv7m-none-eabi`` previously normalized
to ``armv7m-none-unknown-eabi``, with ``none`` for the vendor and ``unknown``
for the operating system. It now normalizes to ``armv7m-unknown-none-eabi``,
which has ``unknown`` vendor and ``none`` operating system.

The affected triples are primarily for bare metal Arm where it is intended
that ``none`` means that there is no operating system. As opposed to an unknown
type of operating system.

This change my cause clang to not find libraries, or libraries to be built at
different file system locations. This can be fixed by changing your builds to
use the new normalized triple. However, we recommend instead getting the
normalized triple from clang itself, as this will make your builds more
robust in case of future changes::

$ clang --target=<your target triple> -print-target-triple
<the normalized target triple>

What's New in Clang |release|?
==============================
Some of the major new features and improvements to Clang are listed
Expand All @@ -94,6 +120,17 @@ sections with improvements to Clang's support for those languages.

C++ Language Changes
--------------------
- C++17 support is now completed, with the enablement of the
relaxed temlate template argument matching rules introduced in P0522,
which was retroactively applied as a defect report.
While the implementation already existed since Clang 4, it was turned off by
default, and was controlled with the `-frelaxed-template-template-args` flag.
In this release, we implement provisional wording for a core defect on
P0522 (CWG2398), which avoids the most serious compatibility issues caused
by it, allowing us to enable it by default in this release.
The flag is now deprecated, and will be removed in the next release, but can
still be used to turn it off and regain compatibility with previous versions
(#GH36505).
- Implemented ``_BitInt`` literal suffixes ``__wb`` or ``__WB`` as a Clang extension with ``unsigned`` modifiers also allowed. (#GH85223).

C++17 Feature Support
Expand Down Expand Up @@ -153,6 +190,9 @@ C++2c Feature Support

- Implemented `P2748R5 Disallow Binding a Returned Glvalue to a Temporary <https://wg21.link/P2748R5>`_.

- Implemented `P2809R3: Trivial infinite loops are not Undefined Behavior <https://wg21.link/P2809R3>`_.


Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Substitute template parameter pack, when it is not explicitly specified
Expand All @@ -173,6 +213,9 @@ Resolutions to C++ Defect Reports
- Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers.
(`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers <https://cplusplus.github.io/CWG/issues/2858.html>`_).

- P0522 implementation is enabled by default in all language versions, and
provisional wording for CWG2398 is implemented.

C Language Changes
------------------

Expand Down Expand Up @@ -294,6 +337,10 @@ Modified Compiler Flags
- Carved out ``-Wformat`` warning about scoped enums into a subwarning and
make it controlled by ``-Wformat-pedantic``. Fixes #GH88595.

- Trivial infinite loops (i.e loops with a constant controlling expresion
evaluating to ``true`` and an empty body such as ``while(1);``)
are considered infinite, even when the ``-ffinite-loop`` flag is set.

Removed Compiler Flags
-------------------------

Expand Down Expand Up @@ -414,6 +461,18 @@ Improvements to Clang's diagnostics

- Clang now diagnoses requires expressions with explicit object parameters.

- Clang now looks up members of the current instantiation in the template definition context
if the current instantiation has no dependent base classes.

.. code-block:: c++

template<typename T>
struct A {
int f() {
return this->x; // error: no member named 'x' in 'A<T>'
}
};

Improvements to Clang's time-trace
----------------------------------

Expand Down Expand Up @@ -460,6 +519,9 @@ Bug Fixes in This Version
- Clang now correctly generates overloads for bit-precise integer types for
builtin operators in C++. Fixes #GH82998.

- Fix crash when destructor definition is preceded with an equals sign.
Fixes (#GH89544).

- When performing mixed arithmetic between ``_Complex`` floating-point types and integers,
Clang now correctly promotes the integer to its corresponding real floating-point
type only rather than to the complex type (e.g. ``_Complex float / int`` is now evaluated
Expand Down Expand Up @@ -487,6 +549,9 @@ Bug Fixes in This Version
The values of 0 and 1 block any unrolling of the loop. This keeps the same behavior with GCC.
Fixes (`#88624 <https://github.com/llvm/llvm-project/issues/88624>`_).

- Clang will no longer emit a duplicate -Wunused-value warning for an expression
`(A, B)` which evaluates to glvalue `B` that can be converted to non ODR-use. (#GH45783)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -614,6 +679,10 @@ Bug Fixes to C++ Support
- Fix a bug on template partial specialization whose template parameter is `decltype(auto)`.
- Fix a bug on template partial specialization with issue on deduction of nontype template parameter
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).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -726,10 +795,10 @@ AIX Support
WebAssembly Support
^^^^^^^^^^^^^^^^^^^

The -mcpu=generic configuration now enables multivalue and reference-types.These
proposals are standardized and available in all major engines. Enabling
multivalue here only enables the language feature but does not turn on the
multivalue ABI (this enables non-ABI uses of multivalue, like exnref).
The -mcpu=generic configuration now enables multivalue feature, which is
standardized and available in all major engines. Enabling multivalue here only
enables the language feature but does not turn on the multivalue ABI (this
enables non-ABI uses of multivalue, like exnref).

AVR Support
^^^^^^^^^^^
Expand Down
3 changes: 1 addition & 2 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1696,7 +1696,6 @@ for more details.
* ``-fno-associative-math``
* ``-fno-reciprocal-math``
* ``-fsigned-zeros``
* ``-ftrapping-math``
* ``-ffp-contract=on``

There is ambiguity about how ``-ffp-contract``,
Expand Down Expand Up @@ -3505,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
11 changes: 1 addition & 10 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3033,13 +3033,6 @@ Further examples of injection vulnerabilities this checker can find.
sprintf(buf, s); // warn: untrusted data used as a format string
}
void test() {
size_t ts;
scanf("%zd", &ts); // 'ts' marked as tainted
int *p = (int *)malloc(ts * sizeof(int));
// warn: untrusted data used as buffer size
}
There are built-in sources, propagations and sinks even if no external taint
configuration is provided.
Expand Down Expand Up @@ -3067,9 +3060,7 @@ Default propagations rules:
Default sinks:
``printf``, ``setproctitle``, ``system``, ``popen``, ``execl``, ``execle``,
``execlp``, ``execv``, ``execvp``, ``execvP``, ``execve``, ``dlopen``,
``memcpy``, ``memmove``, ``strncpy``, ``strndup``, ``malloc``, ``calloc``,
``alloca``, ``memccpy``, ``realloc``, ``bcopy``
``execlp``, ``execv``, ``execvp``, ``execvP``, ``execve``, ``dlopen``
Please note that there are no built-in filter functions.
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
24 changes: 24 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,8 @@ class CXXTemporary {
/// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr.
/// }
/// \endcode
///
/// Destructor might be null if destructor declaration is not valid.
class CXXBindTemporaryExpr : public Expr {
CXXTemporary *Temp = nullptr;
Stmt *SubExpr = nullptr;
Expand Down Expand Up @@ -3161,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
289 changes: 263 additions & 26 deletions clang/include/clang/AST/OpenACCClause.h

Large diffs are not rendered by default.

14 changes: 12 additions & 2 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -2527,6 +2527,9 @@ Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2
"avx", "xop" and largely correspond to the machine specific options handled by
the front end.

Note that this attribute does not apply transitively to nested functions such
as blocks or C++ lambdas.

Additionally, this attribute supports function multiversioning for ELF based
x86/x86-64 targets, which can be used to create multiple implementations of the
same function that will be resolved at runtime based on the priority of their
Expand Down Expand Up @@ -3782,6 +3785,12 @@ for that function.

This attribute is incompatible with the ``always_inline`` and ``minsize``
attributes.

Note that this attribute does not apply recursively to nested functions such as
lambdas or blocks when using declaration-specific attribute syntaxes such as double
square brackets (``[[]]``) or ``__attribute__``. The ``#pragma`` syntax can be
used to apply the attribute to all functions, including nested functions, in a
range of source code.
}];
}

Expand Down Expand Up @@ -5654,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
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ def warn_drv_diagnostics_misexpect_requires_pgo : Warning<
def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
def warn_drv_deprecated_arg : Warning<
"argument '%0' is deprecated, use '%1' instead">, InGroup<Deprecated>;
"argument '%0' is deprecated%select{|, use '%2' instead}1">, InGroup<Deprecated>;
def warn_drv_deprecated_custom : Warning<
"argument '%0' is deprecated, %1">, InGroup<Deprecated>;
def warn_drv_assuming_mfloat_abi_is : Warning<
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def err_no_matching_target : Error<"no matching target found for target variant
def err_unsupported_vendor : Error<"vendor '%0' is not supported: '%1'">;
def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'">;
def err_unsupported_os : Error<"os '%0' is not supported: '%1'">;
def err_cannot_read_alias_list : Error<"could not read alias list '%0': %1">;
def err_cannot_read_input_list : Error<"could not read %select{alias list|filelist}0 '%1': %2">;
} // end of command line category.

let CategoryName = "Verification" in {
Expand Down
37 changes: 35 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -7511,6 +7511,9 @@ def err_nested_non_static_member_use : Error<
def warn_cxx98_compat_non_static_member_use : Warning<
"use of non-static data member %0 in an unevaluated context is "
"incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_form_ptr_to_member_from_parenthesized_expr : Error<
"cannot form pointer to member from a parenthesized expression; "
"did you mean to remove the parentheses?">;
def err_invalid_incomplete_type_use : Error<
"invalid use of incomplete type %0">;
def err_builtin_func_cast_more_than_one_arg : Error<
Expand Down Expand Up @@ -12291,8 +12294,8 @@ def warn_acc_if_self_conflict
"evaluates to true">,
InGroup<DiagGroup<"openacc-self-if-potential-conflict">>;
def err_acc_int_expr_requires_integer
: Error<"OpenACC %select{clause|directive}0 '%1' requires expression of "
"integer type (%2 invalid)">;
: Error<"OpenACC %select{clause '%1'|directive '%2'|sub-array bound}0 "
"requires expression of integer type (%3 invalid)">;
def err_acc_int_expr_incomplete_class_type
: Error<"OpenACC integer expression has incomplete class type %0">;
def err_acc_int_expr_explicit_conversion
Expand All @@ -12307,4 +12310,34 @@ def err_acc_num_gangs_num_args
"OpenACC 'num_gangs' "
"%select{|clause: '%1' directive expects maximum of %2, %3 were "
"provided}0">;
def err_acc_not_a_var_ref
: Error<"OpenACC variable is not a valid variable name, sub-array, array "
"element, or composite variable member">;
def err_acc_typecheck_subarray_value
: Error<"OpenACC sub-array subscripted value is not an array or pointer">;
def err_acc_subarray_function_type
: Error<"OpenACC sub-array cannot be of function type %0">;
def err_acc_subarray_incomplete_type
: Error<"OpenACC sub-array base is of incomplete type %0">;
def err_acc_subarray_no_length
: Error<"OpenACC sub-array length is unspecified and cannot be inferred "
"because the subscripted value is %select{not an array|an array of "
"unknown bound}0">;
def err_acc_subarray_negative
: Error<"OpenACC sub-array %select{lower bound|length}0 evaluated to "
"negative value %1">;
def err_acc_subarray_out_of_range
: Error<"OpenACC sub-array %select{lower bound|length}0 evaluated to a "
"value (%1) that would be out of the range of the subscripted "
"array size of %2">;
def err_acc_subarray_base_plus_length_out_of_range
: Error<"OpenACC sub-array specified range [%0:%1] would be out of the "
"range of the subscripted array size of %2">;
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.
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ LANGOPT(GNUAsm , 1, 1, "GNU-style inline assembly")
LANGOPT(Coroutines , 1, 0, "C++20 coroutines")
LANGOPT(CoroAlignedAllocation, 1, 0, "prefer Aligned Allocation according to P2014 Option 2")
LANGOPT(DllExportInlines , 1, 1, "dllexported classes dllexport inline methods")
LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments")
LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template template arguments")
LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features")

LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
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
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
27 changes: 26 additions & 1 deletion clang/include/clang/Basic/OpenACCClauses.def
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,37 @@
// as used in Clang source (so `Default` instead of `default`).
//
// VISIT_CLAUSE(CLAUSE_NAME)
//
// CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)

#ifndef CLAUSE_ALIAS
#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)
#endif

VISIT_CLAUSE(Attach)
VISIT_CLAUSE(Copy)
CLAUSE_ALIAS(PCopy, Copy)
CLAUSE_ALIAS(PresentOrCopy, Copy)
VISIT_CLAUSE(CopyIn)
CLAUSE_ALIAS(PCopyIn, CopyIn)
CLAUSE_ALIAS(PresentOrCopyIn, CopyIn)
VISIT_CLAUSE(CopyOut)
CLAUSE_ALIAS(PCopyOut, CopyOut)
CLAUSE_ALIAS(PresentOrCopyOut, CopyOut)
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(Self)
VISIT_CLAUSE(NoCreate)
VISIT_CLAUSE(NumGangs)
VISIT_CLAUSE(NumWorkers)
VISIT_CLAUSE(Present)
VISIT_CLAUSE(Private)
VISIT_CLAUSE(Self)
VISIT_CLAUSE(VectorLength)

#undef VISIT_CLAUSE
#undef CLAUSE_ALIAS
45 changes: 44 additions & 1 deletion clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ enum class OpenACCClauseKind {
/// 'copy' clause, allowed on Compute and Combined Constructs, plus 'data' and
/// 'declare'.
Copy,
/// 'copy' clause alias 'pcopy'. Preserved for diagnostic purposes.
PCopy,
/// 'copy' clause alias 'present_or_copy'. Preserved for diagnostic purposes.
PresentOrCopy,
/// 'use_device' clause, allowed on 'host_data' construct.
UseDevice,
/// 'attach' clause, allowed on Compute and Combined constructs, plus 'data'
Expand Down Expand Up @@ -224,12 +228,27 @@ enum class OpenACCClauseKind {
/// 'copyout' clause, allowed on Compute and Combined constructs, plus 'data',
/// 'exit data', and 'declare'.
CopyOut,
/// 'copyout' clause alias 'pcopyout'. Preserved for diagnostic purposes.
PCopyOut,
/// 'copyout' clause alias 'present_or_copyout'. Preserved for diagnostic
/// purposes.
PresentOrCopyOut,
/// 'copyin' clause, allowed on Compute and Combined constructs, plus 'data',
/// 'enter data', and 'declare'.
CopyIn,
/// 'copyin' clause, allowed on Compute and Combined constructs, plus 'data',
/// 'copyin' clause alias 'pcopyin'. Preserved for diagnostic purposes.
PCopyIn,
/// 'copyin' clause alias 'present_or_copyin'. Preserved for diagnostic
/// purposes.
PresentOrCopyIn,
/// 'create' clause, allowed on Compute and Combined constructs, plus 'data',
/// 'enter data', and 'declare'.
Create,
/// 'create' clause alias 'pcreate'. Preserved for diagnostic purposes.
PCreate,
/// 'create' clause alias 'present_or_create'. Preserved for diagnostic
/// purposes.
PresentOrCreate,
/// 'reduction' clause, allowed on Parallel, Serial, Loop, and the combined
/// constructs.
Reduction,
Expand Down Expand Up @@ -310,6 +329,12 @@ inline StreamTy &printOpenACCClauseKind(StreamTy &Out, OpenACCClauseKind K) {
case OpenACCClauseKind::Copy:
return Out << "copy";

case OpenACCClauseKind::PCopy:
return Out << "pcopy";

case OpenACCClauseKind::PresentOrCopy:
return Out << "present_or_copy";

case OpenACCClauseKind::UseDevice:
return Out << "use_device";

Expand Down Expand Up @@ -352,12 +377,30 @@ inline StreamTy &printOpenACCClauseKind(StreamTy &Out, OpenACCClauseKind K) {
case OpenACCClauseKind::CopyOut:
return Out << "copyout";

case OpenACCClauseKind::PCopyOut:
return Out << "pcopyout";

case OpenACCClauseKind::PresentOrCopyOut:
return Out << "present_or_copyout";

case OpenACCClauseKind::CopyIn:
return Out << "copyin";

case OpenACCClauseKind::PCopyIn:
return Out << "pcopyin";

case OpenACCClauseKind::PresentOrCopyIn:
return Out << "present_or_copyin";

case OpenACCClauseKind::Create:
return Out << "create";

case OpenACCClauseKind::PCreate:
return Out << "pcreate";

case OpenACCClauseKind::PresentOrCreate:
return Out << "present_or_create";

case OpenACCClauseKind::Reduction:
return Out << "reduction";

Expand Down
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
3 changes: 2 additions & 1 deletion clang/include/clang/Driver/Distro.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class Distro {
UbuntuLunar,
UbuntuMantic,
UbuntuNoble,
UbuntuOracular,
UnknownDistro
};

Expand Down Expand Up @@ -130,7 +131,7 @@ class Distro {
}

bool IsUbuntu() const {
return DistroVal >= UbuntuHardy && DistroVal <= UbuntuNoble;
return DistroVal >= UbuntuHardy && DistroVal <= UbuntuOracular;
}

bool IsAlpineLinux() const { return DistroVal == AlpineLinux; }
Expand Down
56 changes: 28 additions & 28 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3383,10 +3383,10 @@ defm application_extension : BoolFOption<"application-extension",
"Restrict code to those available for App Extensions">,
NegFlag<SetFalse>>;
defm relaxed_template_template_args : BoolFOption<"relaxed-template-template-args",
LangOpts<"RelaxedTemplateTemplateArgs">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Enable C++17 relaxed template template argument matching">,
NegFlag<SetFalse>>;
LangOpts<"RelaxedTemplateTemplateArgs">, DefaultTrue,
PosFlag<SetTrue, [], [], "Enable">,
NegFlag<SetFalse, [], [CC1Option], "Disable">,
BothFlags<[], [ClangOption], " C++17 relaxed template template argument matching">>;
defm sized_deallocation : BoolFOption<"sized-deallocation",
LangOpts<"SizedDeallocation">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
Expand Down Expand Up @@ -3663,14 +3663,14 @@ defm rwpi : BoolFOption<"rwpi",
"Generate read-write position independent code (ARM only)">,
NegFlag<SetFalse, [], [ClangOption, FlangOption, CC1Option]>>;
def fplugin_EQ : Joined<["-"], "fplugin=">, Group<f_Group>,
Flags<[NoXarchOption]>, MetaVarName<"<dsopath>">,
Flags<[NoXarchOption, NoArgumentUnused]>, MetaVarName<"<dsopath>">,
HelpText<"Load the named plugin (dynamic shared object)">;
def fplugin_arg : Joined<["-"], "fplugin-arg-">,
MetaVarName<"<name>-<arg>">,
MetaVarName<"<name>-<arg>">, Flags<[NoArgumentUnused]>,
HelpText<"Pass <arg> to plugin <name>">;
def fpass_plugin_EQ : Joined<["-"], "fpass-plugin=">,
Group<f_Group>, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
MetaVarName<"<dsopath>">,
MetaVarName<"<dsopath>">, Flags<[NoArgumentUnused]>,
HelpText<"Load pass plugin from a dynamic shared object file (only with new pass manager).">,
MarshallingInfoStringVector<CodeGenOpts<"PassPlugins">>;
defm tocdata : BoolOption<"m","tocdata",
Expand Down Expand Up @@ -3971,7 +3971,7 @@ def funroll_loops : Flag<["-"], "funroll-loops">, Group<f_Group>,
def fno_unroll_loops : Flag<["-"], "fno-unroll-loops">, Group<f_Group>,
HelpText<"Turn off loop unroller">, Visibility<[ClangOption, CC1Option]>;
def ffinite_loops: Flag<["-"], "ffinite-loops">, Group<f_Group>,
HelpText<"Assume all loops are finite.">, Visibility<[ClangOption, CC1Option]>;
HelpText<"Assume all non-trivial loops are finite.">, Visibility<[ClangOption, CC1Option]>;
def fno_finite_loops: Flag<["-"], "fno-finite-loops">, Group<f_Group>,
HelpText<"Do not assume that any loop is finite.">,
Visibility<[ClangOption, CC1Option]>;
Expand Down Expand Up @@ -4895,34 +4895,34 @@ def mharden_sls_EQ : Joined<["-"], "mharden-sls=">, Group<m_Group>,
" blr(ARM/AArch64), comdat(ARM/AArch64), nocomdat(ARM/AArch64),"
" return(X86), indirect-jmp(X86)">;

def msimd128 : Flag<["-"], "msimd128">, Group<m_wasm_Features_Group>;
def mno_simd128 : Flag<["-"], "mno-simd128">, Group<m_wasm_Features_Group>;
def mrelaxed_simd : Flag<["-"], "mrelaxed-simd">, Group<m_wasm_Features_Group>;
def mno_relaxed_simd : Flag<["-"], "mno-relaxed-simd">, Group<m_wasm_Features_Group>;
def mhalf_precision : Flag<["-"], "mhalf-precision">, Group<m_wasm_Features_Group>;
def mno_half_precision : Flag<["-"], "mno-half-precision">, Group<m_wasm_Features_Group>;
def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group<m_wasm_Features_Group>;
def mno_nontrapping_fptoint : Flag<["-"], "mno-nontrapping-fptoint">, Group<m_wasm_Features_Group>;
def msign_ext : Flag<["-"], "msign-ext">, Group<m_wasm_Features_Group>;
def mno_sign_ext : Flag<["-"], "mno-sign-ext">, Group<m_wasm_Features_Group>;
def mexception_handing : Flag<["-"], "mexception-handling">, Group<m_wasm_Features_Group>;
def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group<m_wasm_Features_Group>;
def matomics : Flag<["-"], "matomics">, Group<m_wasm_Features_Group>;
def mno_atomics : Flag<["-"], "mno-atomics">, Group<m_wasm_Features_Group>;
def mbulk_memory : Flag<["-"], "mbulk-memory">, Group<m_wasm_Features_Group>;
def mno_bulk_memory : Flag<["-"], "mno-bulk-memory">, Group<m_wasm_Features_Group>;
def mmutable_globals : Flag<["-"], "mmutable-globals">, Group<m_wasm_Features_Group>;
def mno_mutable_globals : Flag<["-"], "mno-mutable-globals">, Group<m_wasm_Features_Group>;
def mmultivalue : Flag<["-"], "mmultivalue">, Group<m_wasm_Features_Group>;
def mno_multivalue : Flag<["-"], "mno-multivalue">, Group<m_wasm_Features_Group>;
def mtail_call : Flag<["-"], "mtail-call">, Group<m_wasm_Features_Group>;
def mno_tail_call : Flag<["-"], "mno-tail-call">, Group<m_wasm_Features_Group>;
def mreference_types : Flag<["-"], "mreference-types">, Group<m_wasm_Features_Group>;
def mno_reference_types : Flag<["-"], "mno-reference-types">, Group<m_wasm_Features_Group>;
def mexception_handing : Flag<["-"], "mexception-handling">, Group<m_wasm_Features_Group>;
def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group<m_wasm_Features_Group>;
def mextended_const : Flag<["-"], "mextended-const">, Group<m_wasm_Features_Group>;
def mno_extended_const : Flag<["-"], "mno-extended-const">, Group<m_wasm_Features_Group>;
def mhalf_precision : Flag<["-"], "mhalf-precision">, Group<m_wasm_Features_Group>;
def mno_half_precision : Flag<["-"], "mno-half-precision">, Group<m_wasm_Features_Group>;
def mmultimemory : Flag<["-"], "mmultimemory">, Group<m_wasm_Features_Group>;
def mno_multimemory : Flag<["-"], "mno-multimemory">, Group<m_wasm_Features_Group>;
def mmultivalue : Flag<["-"], "mmultivalue">, Group<m_wasm_Features_Group>;
def mno_multivalue : Flag<["-"], "mno-multivalue">, Group<m_wasm_Features_Group>;
def mmutable_globals : Flag<["-"], "mmutable-globals">, Group<m_wasm_Features_Group>;
def mno_mutable_globals : Flag<["-"], "mno-mutable-globals">, Group<m_wasm_Features_Group>;
def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group<m_wasm_Features_Group>;
def mno_nontrapping_fptoint : Flag<["-"], "mno-nontrapping-fptoint">, Group<m_wasm_Features_Group>;
def mreference_types : Flag<["-"], "mreference-types">, Group<m_wasm_Features_Group>;
def mno_reference_types : Flag<["-"], "mno-reference-types">, Group<m_wasm_Features_Group>;
def mrelaxed_simd : Flag<["-"], "mrelaxed-simd">, Group<m_wasm_Features_Group>;
def mno_relaxed_simd : Flag<["-"], "mno-relaxed-simd">, Group<m_wasm_Features_Group>;
def msign_ext : Flag<["-"], "msign-ext">, Group<m_wasm_Features_Group>;
def mno_sign_ext : Flag<["-"], "mno-sign-ext">, Group<m_wasm_Features_Group>;
def msimd128 : Flag<["-"], "msimd128">, Group<m_wasm_Features_Group>;
def mno_simd128 : Flag<["-"], "mno-simd128">, Group<m_wasm_Features_Group>;
def mtail_call : Flag<["-"], "mtail-call">, Group<m_wasm_Features_Group>;
def mno_tail_call : Flag<["-"], "mno-tail-call">, Group<m_wasm_Features_Group>;
def mexec_model_EQ : Joined<["-"], "mexec-model=">, Group<m_wasm_Features_Driver_Group>,
Values<"command,reactor">,
HelpText<"Execution model (WebAssembly only)">,
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,8 @@ struct FormatStyle {
/// }
/// \endcode
bool AcrossComments;
/// Whether aligned case labels are aligned on the colon, or on the
/// , or on the tokens after the colon.
/// Whether aligned case labels are aligned on the colon, or on the tokens
/// after the colon.
/// \code
/// true:
/// switch (level) {
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/InstallAPI/FileList.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ class FileListReader {
///
/// \param InputBuffer JSON input data.
/// \param Destination Container to load headers into.
/// \param FM Optional File Manager to validate input files exist.
static llvm::Error
loadHeaders(std::unique_ptr<llvm::MemoryBuffer> InputBuffer,
HeaderSeq &Destination);
HeaderSeq &Destination, clang::FileManager *FM = nullptr);

FileListReader() = delete;
};
Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3654,11 +3654,12 @@ class Parser : public CodeCompletionHandler {
ExprResult ParseOpenACCIDExpression();
/// Parses the variable list for the `cache` construct.
void ParseOpenACCCacheVarList();

using OpenACCVarParseResult = std::pair<ExprResult, OpenACCParseCanContinue>;
/// Parses a single variable in a variable list for OpenACC.
bool ParseOpenACCVar();
/// Parses the variable list for the variety of clauses that take a var-list,
/// including the optional Special Token listed for some,based on clause type.
bool ParseOpenACCClauseVarList(OpenACCClauseKind Kind);
OpenACCVarParseResult ParseOpenACCVar();
/// Parses the variable list for the variety of places that take a var-list.
llvm::SmallVector<Expr *> ParseOpenACCVarList();
/// Parses any parameters for an OpenACC Clause, including required/optional
/// parens.
OpenACCClauseParseResult
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Sema/Lookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,9 @@ class LookupResult {
/// Note that while no result was found in the current instantiation,
/// there were dependent base classes that could not be searched.
void setNotFoundInCurrentInstantiation() {
assert(ResultKind == NotFound && Decls.empty());
assert((ResultKind == NotFound ||
ResultKind == NotFoundInCurrentInstantiation) &&
Decls.empty());
ResultKind = NotFoundInCurrentInstantiation;
}

Expand Down
30 changes: 13 additions & 17 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4097,12 +4097,12 @@ class Sema final : public SemaBase {
SmallVectorImpl<QualType> &Exceptions,
FunctionProtoType::ExceptionSpecInfo &ESI);

/// Add an exception-specification to the given member function
/// (or member function template). The exception-specification was parsed
/// after the method itself was declared.
/// Add an exception-specification to the given member or friend function
/// (or function template). The exception-specification was parsed
/// after the function itself was declared.
void actOnDelayedExceptionSpecification(
Decl *Method, ExceptionSpecificationType EST,
SourceRange SpecificationRange, ArrayRef<ParsedType> DynamicExceptions,
Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange,
ArrayRef<ParsedType> DynamicExceptions,
ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr);

class InheritedConstructorInfo;
Expand Down Expand Up @@ -6978,12 +6978,6 @@ class Sema final : public SemaBase {
SourceLocation TemplateKWLoc,
UnqualifiedId &Member, Decl *ObjCImpDecl);

MemberExpr *BuildMemberExpr(
Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS,
SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl,
bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo,
QualType Ty, ExprValueKind VK, ExprObjectKind OK,
const TemplateArgumentListInfo *TemplateArgs = nullptr);
MemberExpr *
BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc,
NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
Expand Down Expand Up @@ -7472,7 +7466,7 @@ class Sema final : public SemaBase {
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
CXXScopeSpec &SS);
bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
QualType ObjectType, bool AllowBuiltinCreation = false,
bool EnteringContext = false);
ObjCProtocolDecl *LookupProtocol(
IdentifierInfo *II, SourceLocation IdLoc,
Expand Down Expand Up @@ -8881,11 +8875,13 @@ class Sema final : public SemaBase {
/// functions (but no function templates).
FoundFunctions,
};
bool LookupTemplateName(
LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
bool EnteringContext, bool &MemberOfUnknownSpecialization,
RequiredTemplateKind RequiredTemplate = SourceLocation(),
AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);

bool
LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
QualType ObjectType, bool EnteringContext,
RequiredTemplateKind RequiredTemplate = SourceLocation(),
AssumedTemplateKind *ATK = nullptr,
bool AllowTypoCorrection = true);

TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
bool hasTemplateKeyword,
Expand Down
Loading