63 changes: 34 additions & 29 deletions bolt/lib/Rewrite/DWARFRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ namespace bolt {
/// Emits debug information into .debug_info or .debug_types section.
class DIEStreamer : public DwarfStreamer {
DIEBuilder *DIEBldr;
DWARFRewriter &Rewriter;
GDBIndex &GDBIndexSection;

private:
/// Emit the compilation unit header for \p Unit in the debug_info
Expand Down Expand Up @@ -247,7 +247,7 @@ class DIEStreamer : public DwarfStreamer {
const uint64_t TypeSignature = cast<DWARFTypeUnit>(Unit).getTypeHash();
DIE *TypeDIE = DIEBldr->getTypeDIE(Unit);
const DIEBuilder::DWARFUnitInfo &UI = DIEBldr->getUnitInfoByDwarfUnit(Unit);
Rewriter.addGDBTypeUnitEntry(
GDBIndexSection.addGDBTypeUnitEntry(
{UI.UnitOffset, TypeSignature, TypeDIE->getOffset()});
if (Unit.getVersion() < 5) {
// Switch the section to .debug_types section.
Expand Down Expand Up @@ -278,12 +278,12 @@ class DIEStreamer : public DwarfStreamer {
}

public:
DIEStreamer(DIEBuilder *DIEBldr, DWARFRewriter &Rewriter,
DIEStreamer(DIEBuilder *DIEBldr, GDBIndex &GDBIndexSection,
DWARFLinkerBase::OutputFileType OutFileType,
raw_pwrite_stream &OutFile,
DWARFLinkerBase::MessageHandlerTy Warning)
: DwarfStreamer(OutFileType, OutFile, Warning), DIEBldr(DIEBldr),
Rewriter(Rewriter){};
GDBIndexSection(GDBIndexSection) {};

using DwarfStreamer::emitCompileUnitHeader;

Expand Down Expand Up @@ -326,12 +326,11 @@ static cl::opt<bool> KeepARanges(
"keep or generate .debug_aranges section if .gdb_index is written"),
cl::Hidden, cl::cat(BoltCategory));

static cl::opt<bool>
DeterministicDebugInfo("deterministic-debuginfo",
cl::desc("disables parallel execution of tasks that may produce "
"nondeterministic debug info"),
cl::init(true),
cl::cat(BoltCategory));
static cl::opt<bool> DeterministicDebugInfo(
"deterministic-debuginfo",
cl::desc("disables parallel execution of tasks that may produce "
"nondeterministic debug info"),
cl::init(true), cl::cat(BoltCategory));

static cl::opt<std::string> DwarfOutputPath(
"dwarf-output-path",
Expand Down Expand Up @@ -460,10 +459,11 @@ static std::optional<uint64_t> getAsAddress(const DWARFUnit &DU,
static std::unique_ptr<DIEStreamer>
createDIEStreamer(const Triple &TheTriple, raw_pwrite_stream &OutFile,
StringRef Swift5ReflectionSegmentName, DIEBuilder &DIEBldr,
DWARFRewriter &Rewriter) {
GDBIndex &GDBIndexSection) {

std::unique_ptr<DIEStreamer> Streamer = std::make_unique<DIEStreamer>(
&DIEBldr, Rewriter, DWARFLinkerBase::OutputFileType::Object, OutFile,
&DIEBldr, GDBIndexSection, DWARFLinkerBase::OutputFileType::Object,
OutFile,
[&](const Twine &Warning, StringRef Context, const DWARFDie *) {});
Error Err = Streamer->init(TheTriple, Swift5ReflectionSegmentName);
if (Err)
Expand All @@ -484,13 +484,12 @@ emitUnit(DIEBuilder &DIEBldr, DIEStreamer &Streamer, DWARFUnit &Unit) {
return {U.UnitOffset, U.UnitLength, TypeHash};
}

static void emitDWOBuilder(const std::string &DWOName,
DIEBuilder &DWODIEBuilder, DWARFRewriter &Rewriter,
DWARFUnit &SplitCU, DWARFUnit &CU,
DWARFRewriter::DWPState &State,
DebugLocWriter &LocWriter,
DebugStrOffsetsWriter &StrOffstsWriter,
DebugStrWriter &StrWriter) {
static void
emitDWOBuilder(const std::string &DWOName, DIEBuilder &DWODIEBuilder,
DWARFRewriter &Rewriter, DWARFUnit &SplitCU, DWARFUnit &CU,
DWARFRewriter::DWPState &State, DebugLocWriter &LocWriter,
DebugStrOffsetsWriter &StrOffstsWriter,
DebugStrWriter &StrWriter, GDBIndex &GDBIndexSection) {
// Populate debug_info and debug_abbrev for current dwo into StringRef.
DWODIEBuilder.generateAbbrevs();
DWODIEBuilder.finish();
Expand All @@ -500,8 +499,9 @@ static void emitDWOBuilder(const std::string &DWOName,
std::make_shared<raw_svector_ostream>(OutBuffer);
const object::ObjectFile *File = SplitCU.getContext().getDWARFObj().getFile();
auto TheTriple = std::make_unique<Triple>(File->makeTriple());
std::unique_ptr<DIEStreamer> Streamer = createDIEStreamer(
*TheTriple, *ObjOS, "DwoStreamerInitAug2", DWODIEBuilder, Rewriter);
std::unique_ptr<DIEStreamer> Streamer =
createDIEStreamer(*TheTriple, *ObjOS, "DwoStreamerInitAug2",
DWODIEBuilder, GDBIndexSection);
DWARFRewriter::UnitMetaVectorType TUMetaVector;
DWARFRewriter::UnitMeta CUMI = {0, 0, 0};
if (SplitCU.getContext().getMaxDWOVersion() >= 5) {
Expand Down Expand Up @@ -652,6 +652,7 @@ void DWARFRewriter::updateDebugInfo() {

DWARF5AcceleratorTable DebugNamesTable(opts::CreateDebugNames, BC,
*StrWriter);
GDBIndex GDBIndexSection(BC);
DWPState State;
if (opts::WriteDWP)
initDWPState(State);
Expand Down Expand Up @@ -704,7 +705,8 @@ void DWARFRewriter::updateDebugInfo() {
TempRangesSectionWriter->finalizeSection();

emitDWOBuilder(DWOName, DWODIEBuilder, *this, **SplitCU, *Unit, State,
DebugLocDWoWriter, DWOStrOffstsWriter, DWOStrWriter);
DebugLocDWoWriter, DWOStrOffstsWriter, DWOStrWriter,
GDBIndexSection);
}

if (Unit->getVersion() >= 5) {
Expand All @@ -729,9 +731,10 @@ void DWARFRewriter::updateDebugInfo() {
std::make_unique<raw_svector_ostream>(OutBuffer);
const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile();
auto TheTriple = std::make_unique<Triple>(File->makeTriple());
std::unique_ptr<DIEStreamer> Streamer =
createDIEStreamer(*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, *this);
CUOffsetMap OffsetMap = finalizeTypeSections(DIEBlder, *Streamer);
std::unique_ptr<DIEStreamer> Streamer = createDIEStreamer(
*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, GDBIndexSection);
CUOffsetMap OffsetMap =
finalizeTypeSections(DIEBlder, *Streamer, GDBIndexSection);

const bool SingleThreadedMode =
opts::NoThreads || opts::DeterministicDebugInfo;
Expand Down Expand Up @@ -761,7 +764,8 @@ void DWARFRewriter::updateDebugInfo() {

finalizeDebugSections(DIEBlder, DebugNamesTable, *Streamer, *ObjOS,
OffsetMap);
updateGdbIndexSection(OffsetMap, CUIndex);
GDBIndexSection.updateGdbIndexSection(OffsetMap, CUIndex,
*ARangesSectionWriter);
}

void DWARFRewriter::updateUnitDebugInfo(
Expand Down Expand Up @@ -1429,7 +1433,8 @@ void DWARFRewriter::updateLineTableOffsets(const MCAsmLayout &Layout) {
}

CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
DIEStreamer &Streamer) {
DIEStreamer &Streamer,
GDBIndex &GDBIndexSection) {
// update TypeUnit DW_AT_stmt_list with new .debug_line information.
auto updateLineTable = [&](const DWARFUnit &Unit) -> void {
DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(Unit);
Expand All @@ -1449,8 +1454,8 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
std::make_shared<raw_svector_ostream>(OutBuffer);
const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile();
auto TheTriple = std::make_unique<Triple>(File->makeTriple());
std::unique_ptr<DIEStreamer> TypeStreamer =
createDIEStreamer(*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, *this);
std::unique_ptr<DIEStreamer> TypeStreamer = createDIEStreamer(
*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, GDBIndexSection);

// generate debug_info and CUMap
CUOffsetMap CUMap;
Expand Down
7 changes: 3 additions & 4 deletions bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
return getTargetAddend(Op.getExpr());
}

bool replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
void replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
MCContext *Ctx) const override {
assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&
"Invalid instruction");
Expand All @@ -638,7 +638,6 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {

*OI = MCOperand::createExpr(
MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
return true;
}

/// Matches indirect branch patterns in AArch64 related to a jump table (JT),
Expand Down Expand Up @@ -969,7 +968,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
}
}

bool reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
void reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
MCContext *Ctx) const override {
if (isTB(Inst) || isCB(Inst)) {
Inst.setOpcode(getInvertedBranchOpcode(Inst.getOpcode()));
Expand All @@ -984,7 +983,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
LLVM_DEBUG(Inst.dump());
llvm_unreachable("Unrecognized branch instruction");
}
return replaceBranchTarget(Inst, TBB, Ctx);
replaceBranchTarget(Inst, TBB, Ctx);
}

int getPCRelEncodingSize(const MCInst &Inst) const override {
Expand Down
7 changes: 3 additions & 4 deletions bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,14 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
}
}

bool reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
void reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
MCContext *Ctx) const override {
auto Opcode = getInvertedBranchOpcode(Inst.getOpcode());
Inst.setOpcode(Opcode);
return replaceBranchTarget(Inst, TBB, Ctx);
replaceBranchTarget(Inst, TBB, Ctx);
}

bool replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
void replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
MCContext *Ctx) const override {
assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&
"Invalid instruction");
Expand All @@ -170,7 +170,6 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {

Inst.getOperand(SymOpIndex) = MCOperand::createExpr(
MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
return true;
}

IndirectBranchType analyzeIndirectBranch(
Expand Down
6 changes: 2 additions & 4 deletions bolt/lib/Target/X86/X86MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2794,14 +2794,13 @@ class X86MCPlusBuilder : public MCPlusBuilder {
Inst.addOperand(MCOperand::createImm(CC));
}

bool reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
void reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
MCContext *Ctx) const override {
unsigned InvCC = getInvertedCondCode(getCondCode(Inst));
assert(InvCC != X86::COND_INVALID && "invalid branch instruction");
Inst.getOperand(Info->get(Inst.getOpcode()).NumOperands - 1).setImm(InvCC);
Inst.getOperand(0) = MCOperand::createExpr(
MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
return true;
}

bool replaceBranchCondition(MCInst &Inst, const MCSymbol *TBB, MCContext *Ctx,
Expand Down Expand Up @@ -2844,13 +2843,12 @@ class X86MCPlusBuilder : public MCPlusBuilder {
}
}

bool replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
void replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
MCContext *Ctx) const override {
assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&
"Invalid instruction");
Inst.getOperand(0) = MCOperand::createExpr(
MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
return true;
}

MCPhysReg getX86R11() const override { return X86::R11; }
Expand Down
6 changes: 2 additions & 4 deletions clang-tools-extra/clang-query/QueryParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,11 @@ QueryRef QueryParser::endQuery(QueryRef Q) {
StringRef Extra = Line;
StringRef ExtraTrimmed = Extra.ltrim(" \t\v\f\r");

if ((!ExtraTrimmed.empty() && ExtraTrimmed[0] == '\n') ||
(ExtraTrimmed.size() >= 2 && ExtraTrimmed[0] == '\r' &&
ExtraTrimmed[1] == '\n'))
if (ExtraTrimmed.starts_with('\n') || ExtraTrimmed.starts_with("\r\n"))
Q->RemainingContent = Extra;
else {
StringRef TrailingWord = lexWord();
if (!TrailingWord.empty() && TrailingWord.front() == '#') {
if (TrailingWord.starts_with('#')) {
Line = Line.drop_until([](char c) { return c == '\n'; });
Line = Line.drop_while([](char c) { return c == '\n'; });
return endQuery(Q);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,21 @@ AST_MATCHER(ImplicitCastExpr, isMultiLevelPointerConversion) {
return SourcePtrLevel != TargetPtrLevel;
}

AST_MATCHER(QualType, isPointerType) {
const QualType Type =
Node.getCanonicalType().getNonReferenceType().getUnqualifiedType();

return !Type.isNull() && Type->isPointerType();
}

} // namespace

void MultiLevelImplicitPointerConversionCheck::registerMatchers(
MatchFinder *Finder) {
Finder->addMatcher(
implicitCastExpr(hasCastKind(CK_BitCast), isMultiLevelPointerConversion())
implicitCastExpr(hasCastKind(CK_BitCast), isMultiLevelPointerConversion(),
unless(hasParent(explicitCastExpr(
hasDestinationType(isPointerType())))))
.bind("expr"),
this);
}
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/misc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ add_clang_library(clangTidyMiscModule
UnusedParametersCheck.cpp
UnusedUsingDeclsCheck.cpp
UseAnonymousNamespaceCheck.cpp
UseInternalLinkageCheck.cpp

LINK_LIBS
clangTidy
Expand Down
13 changes: 4 additions & 9 deletions clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,20 +130,15 @@ class CyclicDependencyCallbacks : public PPCallbacks {
<< FileName;

const bool IsIncludePathValid =
std::all_of(Files.rbegin(), It, [](const Include &Elem) {
std::all_of(Files.rbegin(), It + 1, [](const Include &Elem) {
return !Elem.Name.empty() && Elem.Loc.isValid();
});

if (!IsIncludePathValid)
return;

auto CurrentIt = Files.rbegin();
do {
if (CurrentIt->Loc.isValid())
Check.diag(CurrentIt->Loc, "'%0' included from here",
DiagnosticIDs::Note)
<< CurrentIt->Name;
} while (CurrentIt++ != It);
for (const Include &I : llvm::make_range(Files.rbegin(), It + 1))
Check.diag(I.Loc, "'%0' included from here", DiagnosticIDs::Note)
<< I.Name;
}

bool isFileIgnored(StringRef FileName) const {
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "UnusedParametersCheck.h"
#include "UnusedUsingDeclsCheck.h"
#include "UseAnonymousNamespaceCheck.h"
#include "UseInternalLinkageCheck.h"

namespace clang::tidy {
namespace misc {
Expand Down Expand Up @@ -78,6 +79,8 @@ class MiscModule : public ClangTidyModule {
"misc-unused-using-decls");
CheckFactories.registerCheck<UseAnonymousNamespaceCheck>(
"misc-use-anonymous-namespace");
CheckFactories.registerCheck<UseInternalLinkageCheck>(
"misc-use-internal-linkage");
}
};

Expand Down
95 changes: 95 additions & 0 deletions clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//===--- UseInternalLinkageCheck.cpp - clang-tidy--------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "UseInternalLinkageCheck.h"
#include "../utils/FileExtensionsUtils.h"
#include "clang/AST/Decl.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersMacros.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/STLExtras.h"

using namespace clang::ast_matchers;

namespace clang::tidy::misc {

namespace {

AST_MATCHER(Decl, isFirstDecl) { return Node.isFirstDecl(); }

static bool isInMainFile(SourceLocation L, SourceManager &SM,
const FileExtensionsSet &HeaderFileExtensions) {
for (;;) {
if (utils::isSpellingLocInHeaderFile(L, SM, HeaderFileExtensions))
return false;
if (SM.isInMainFile(L))
return true;
// not in header file but not in main file
L = SM.getIncludeLoc(SM.getFileID(L));
if (L.isValid())
continue;
// Conservative about the unknown
return false;
}
}

AST_MATCHER_P(Decl, isAllRedeclsInMainFile, FileExtensionsSet,
HeaderFileExtensions) {
return llvm::all_of(Node.redecls(), [&](const Decl *D) {
return isInMainFile(D->getLocation(),
Finder->getASTContext().getSourceManager(),
HeaderFileExtensions);
});
}

AST_POLYMORPHIC_MATCHER(isExternStorageClass,
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
VarDecl)) {
return Node.getStorageClass() == SC_Extern;
}

} // namespace

void UseInternalLinkageCheck::registerMatchers(MatchFinder *Finder) {
auto Common =
allOf(isFirstDecl(), isAllRedeclsInMainFile(HeaderFileExtensions),
unless(anyOf(
// 1. internal linkage
isStaticStorageClass(), isInAnonymousNamespace(),
// 2. explicit external linkage
isExternStorageClass(), isExternC(),
// 3. template
isExplicitTemplateSpecialization(),
// 4. friend
hasAncestor(friendDecl()))));
Finder->addMatcher(
functionDecl(Common, unless(cxxMethodDecl()), unless(isMain()))
.bind("fn"),
this);
Finder->addMatcher(varDecl(Common, hasGlobalStorage()).bind("var"), this);
}

static constexpr StringRef Message =
"%0 %1 can be made static or moved into an anonymous namespace "
"to enforce internal linkage";

void UseInternalLinkageCheck::check(const MatchFinder::MatchResult &Result) {
if (const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("fn")) {
diag(FD->getLocation(), Message) << "function" << FD;
return;
}
if (const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var")) {
diag(VD->getLocation(), Message) << "variable" << VD;
return;
}
llvm_unreachable("");
}

} // namespace clang::tidy::misc
38 changes: 38 additions & 0 deletions clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===--- UseInternalLinkageCheck.h - clang-tidy -----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEINTERNALLINKAGECHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEINTERNALLINKAGECHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::misc {

/// Detects variables and functions that can be marked as static or moved into
/// an anonymous namespace to enforce internal linkage.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/misc/use-internal-linkage.html
class UseInternalLinkageCheck : public ClangTidyCheck {
public:
UseInternalLinkageCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
HeaderFileExtensions(Context->getHeaderFileExtensions()) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}

private:
FileExtensionsSet HeaderFileExtensions;
};

} // namespace clang::tidy::misc

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEINTERNALLINKAGECHECK_H
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ static constexpr bool RestrictToPODTypesDefault = false;
static constexpr char IgnoreMacrosName[] = "IgnoreMacros";
static constexpr bool IgnoreMacrosDefault = true;

static constexpr char StrictCStandardComplianceName[] =
"StrictCStandardCompliance";
static constexpr bool StrictCStandardComplianceDefault = true;

static constexpr char StrictCppStandardComplianceName[] =
"StrictCppStandardCompliance";
static constexpr bool StrictCppStandardComplianceDefault = true;

namespace {

struct Designators {
Expand Down Expand Up @@ -97,7 +105,12 @@ UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
RestrictToPODTypes(
Options.get(RestrictToPODTypesName, RestrictToPODTypesDefault)),
IgnoreMacros(
Options.getLocalOrGlobal(IgnoreMacrosName, IgnoreMacrosDefault)) {}
Options.getLocalOrGlobal(IgnoreMacrosName, IgnoreMacrosDefault)),
StrictCStandardCompliance(Options.get(StrictCStandardComplianceName,
StrictCStandardComplianceDefault)),
StrictCppStandardCompliance(
Options.get(StrictCppStandardComplianceName,
StrictCppStandardComplianceDefault)) {}

void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
const auto HasBaseWithFields =
Expand Down Expand Up @@ -179,6 +192,9 @@ void UseDesignatedInitializersCheck::storeOptions(
IgnoreSingleElementAggregates);
Options.store(Opts, RestrictToPODTypesName, RestrictToPODTypes);
Options.store(Opts, IgnoreMacrosName, IgnoreMacros);
Options.store(Opts, StrictCStandardComplianceName, StrictCStandardCompliance);
Options.store(Opts, StrictCppStandardComplianceName,
StrictCppStandardCompliance);
}

} // namespace clang::tidy::modernize
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,19 @@ class UseDesignatedInitializersCheck : public ClangTidyCheck {
return TK_IgnoreUnlessSpelledInSource;
}

bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus20 || LangOpts.C99 ||
(LangOpts.CPlusPlus && !StrictCppStandardCompliance) ||
(!LangOpts.CPlusPlus && !LangOpts.ObjC &&
!StrictCStandardCompliance);
}

private:
bool IgnoreSingleElementAggregates;
bool RestrictToPODTypes;
bool IgnoreMacros;
bool StrictCStandardCompliance;
bool StrictCppStandardCompliance;
};

} // namespace clang::tidy::modernize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,16 @@ void recordRemoval(const DeclStmt &Stmt, ASTContext &Context,
}
}

AST_MATCHER_FUNCTION_P(StatementMatcher, isConstRefReturningMethodCall,
AST_MATCHER_FUNCTION_P(StatementMatcher,
isRefReturningMethodCallWithConstOverloads,
std::vector<StringRef>, ExcludedContainerTypes) {
// Match method call expressions where the `this` argument is only used as
// const, this will be checked in `check()` part. This returned const
// reference is highly likely to outlive the local const reference of the
// variable being declared. The assumption is that the const reference being
// returned either points to a global static variable or to a member of the
// called object.
// const, this will be checked in `check()` part. This returned reference is
// highly likely to outlive the local const reference of the variable being
// declared. The assumption is that the reference being returned either points
// to a global static variable or to a member of the called object.
const auto MethodDecl =
cxxMethodDecl(returns(hasCanonicalType(matchers::isReferenceToConst())))
cxxMethodDecl(returns(hasCanonicalType(referenceType())))
.bind(MethodDeclId);
const auto ReceiverExpr =
ignoringParenImpCasts(declRefExpr(to(varDecl().bind(ObjectArgId))));
Expand Down Expand Up @@ -121,7 +121,7 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, initializerReturnsReferenceToConst,
declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId)));
return expr(
anyOf(isConstRefReturningFunctionCall(),
isConstRefReturningMethodCall(ExcludedContainerTypes),
isRefReturningMethodCallWithConstOverloads(ExcludedContainerTypes),
ignoringImpCasts(OldVarDeclRef),
ignoringImpCasts(unaryOperator(hasOperatorName("&"),
hasUnaryOperand(OldVarDeclRef)))));
Expand Down Expand Up @@ -259,10 +259,11 @@ void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
.bind("blockStmt");
};

Finder->addMatcher(LocalVarCopiedFrom(anyOf(isConstRefReturningFunctionCall(),
isConstRefReturningMethodCall(
ExcludedContainerTypes))),
this);
Finder->addMatcher(
LocalVarCopiedFrom(anyOf(
isConstRefReturningFunctionCall(),
isRefReturningMethodCallWithConstOverloads(ExcludedContainerTypes))),
this);

Finder->addMatcher(LocalVarCopiedFrom(declRefExpr(
to(varDecl(hasLocalStorage()).bind(OldVarDeclId)))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,9 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
hasParent(callExpr()),
hasSourceExpression(binaryOperator(hasAnyOperatorName("==", "!="))));

auto IsInCompilerGeneratedFunction = hasAncestor(namedDecl(anyOf(
isImplicit(), functionDecl(isDefaulted()), functionTemplateDecl())));

Finder->addMatcher(
traverse(TK_AsIs,
implicitCastExpr(
Expand All @@ -299,7 +302,7 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
// additional parens in replacement.
optionally(hasParent(stmt().bind("parentStmt"))),
unless(isInTemplateInstantiation()),
unless(hasAncestor(functionTemplateDecl())))
unless(IsInCompilerGeneratedFunction))
.bind("implicitCastToBool")),
this);

Expand Down Expand Up @@ -331,7 +334,7 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
anyOf(hasParent(implicitCastExpr().bind("furtherImplicitCast")),
anything()),
unless(isInTemplateInstantiation()),
unless(hasAncestor(functionTemplateDecl())))),
unless(IsInCompilerGeneratedFunction))),
this);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ static void addParantheses(const BinaryOperator *BinOp,
int Precedence1 = getPrecedence(BinOp);
int Precedence2 = getPrecedence(ParentBinOp);

if (ParentBinOp != nullptr && Precedence1 != Precedence2) {
if (ParentBinOp != nullptr && Precedence1 != Precedence2 && Precedence1 > 0 &&
Precedence2 > 0) {
const clang::SourceLocation StartLoc = BinOp->getBeginLoc();
const clang::SourceLocation EndLoc =
clang::Lexer::getLocForEndOfToken(BinOp->getEndLoc(), 0, SM, LangOpts);
Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def main():
filename = None
lines_by_file = {}
for line in sys.stdin:
match = re.search('^\+\+\+\ "?(.*?/){%s}([^ \t\n"]*)' % args.p, line)
match = re.search('^\\+\\+\\+\\ "?(.*?/){%s}([^ \t\n"]*)' % args.p, line)
if match:
filename = match.group(2)
if filename is None:
Expand All @@ -255,7 +255,7 @@ def main():
if not re.match("^%s$" % args.iregex, filename, re.IGNORECASE):
continue

match = re.search("^@@.*\+(\d+)(,(\d+))?", line)
match = re.search(r"^@@.*\+(\d+)(,(\d+))?", line)
if match:
start_line = int(match.group(1))
line_count = 1
Expand Down
168 changes: 161 additions & 7 deletions clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,116 @@ void extractNodesByIdTo(ArrayRef<BoundNodes> Matches, StringRef ID,
Nodes.insert(Match.getNodeAs<Node>(ID));
}

// Returns true if both types refer to the same type,
// ignoring the const-qualifier.
bool isSameTypeIgnoringConst(QualType A, QualType B) {
A = A.getCanonicalType();
B = B.getCanonicalType();
A.addConst();
B.addConst();
return A == B;
}

// Returns true if `D` and `O` have the same parameter types.
bool hasSameParameterTypes(const CXXMethodDecl &D, const CXXMethodDecl &O) {
if (D.getNumParams() != O.getNumParams())
return false;
for (int I = 0, E = D.getNumParams(); I < E; ++I) {
if (!isSameTypeIgnoringConst(D.getParamDecl(I)->getType(),
O.getParamDecl(I)->getType()))
return false;
}
return true;
}

// If `D` has a const-qualified overload with otherwise identical
// ref-qualifiers and parameter types, returns that overload.
const CXXMethodDecl *findConstOverload(const CXXMethodDecl &D) {
assert(!D.isConst());

DeclContext::lookup_result LookupResult =
D.getParent()->lookup(D.getNameInfo().getName());
if (LookupResult.isSingleResult()) {
// No overload.
return nullptr;
}
for (const Decl *Overload : LookupResult) {
const auto *O = dyn_cast<CXXMethodDecl>(Overload);
if (O && !O->isDeleted() && O->isConst() &&
O->getRefQualifier() == D.getRefQualifier() &&
hasSameParameterTypes(D, *O))
return O;
}
return nullptr;
}

// Returns true if both types are pointers or reference to the same type,
// ignoring the const-qualifier.
bool pointsToSameTypeIgnoringConst(QualType A, QualType B) {
assert(A->isPointerType() || A->isReferenceType());
assert(B->isPointerType() || B->isReferenceType());
return isSameTypeIgnoringConst(A->getPointeeType(), B->getPointeeType());
}

// Return true if non-const member function `M` likely does not mutate `*this`.
//
// Note that if the member call selects a method/operator `f` that
// is not const-qualified, then we also consider that the object is
// not mutated if:
// - (A) there is a const-qualified overload `cf` of `f` that has
// the
// same ref-qualifiers;
// - (B) * `f` returns a value, or
// * if `f` returns a `T&`, `cf` returns a `const T&` (up to
// possible aliases such as `reference` and
// `const_reference`), or
// * if `f` returns a `T*`, `cf` returns a `const T*` (up to
// possible aliases).
// - (C) the result of the call is not mutated.
//
// The assumption that `cf` has the same semantics as `f`.
// For example:
// - In `std::vector<T> v; const T t = v[...];`, we consider that
// expression `v[...]` does not mutate `v` as
// `T& std::vector<T>::operator[]` has a const overload
// `const T& std::vector<T>::operator[] const`, and the
// result expression of type `T&` is only used as a `const T&`;
// - In `std::map<K, V> m; V v = m.at(...);`, we consider
// `m.at(...)` to be an immutable access for the same reason.
// However:
// - In `std::map<K, V> m; const V v = m[...];`, We consider that
// `m[...]` mutates `m` as `V& std::map<K, V>::operator[]` does
// not have a const overload.
// - In `std::vector<T> v; T& t = v[...];`, we consider that
// expression `v[...]` mutates `v` as the result is kept as a
// mutable reference.
//
// This function checks (A) ad (B), but the caller should make sure that the
// object is not mutated through the return value.
bool isLikelyShallowConst(const CXXMethodDecl &M) {
assert(!M.isConst());
// The method can mutate our variable.

// (A)
const CXXMethodDecl *ConstOverload = findConstOverload(M);
if (ConstOverload == nullptr) {
return false;
}

// (B)
const QualType CallTy = M.getReturnType().getCanonicalType();
const QualType OverloadTy = ConstOverload->getReturnType().getCanonicalType();
if (CallTy->isReferenceType()) {
return OverloadTy->isReferenceType() &&
pointsToSameTypeIgnoringConst(CallTy, OverloadTy);
}
if (CallTy->isPointerType()) {
return OverloadTy->isPointerType() &&
pointsToSameTypeIgnoringConst(CallTy, OverloadTy);
}
return isSameTypeIgnoringConst(CallTy, OverloadTy);
}

// A matcher that matches DeclRefExprs that are used in ways such that the
// underlying declaration is not modified.
// If the declaration is of pointer type, `Indirections` specifies the level
Expand All @@ -54,16 +164,15 @@ void extractNodesByIdTo(ArrayRef<BoundNodes> Matches, StringRef ID,
// matches (A).
//
AST_MATCHER_P(DeclRefExpr, doesNotMutateObject, int, Indirections) {
// We walk up the parents of the DeclRefExpr recursively until we end up on a
// parent that cannot modify the underlying object. There are a few kinds of
// expressions:
// - Those that cannot be used to mutate the underlying object. We can stop
// We walk up the parents of the DeclRefExpr recursively. There are a few
// kinds of expressions:
// - Those that cannot be used to mutate the underlying variable. We can stop
// recursion there.
// - Those that can be used to mutate the underlying object in analyzable
// - Those that can be used to mutate the underlying variable in analyzable
// ways (such as taking the address or accessing a subobject). We have to
// examine the parents.
// - Those that we don't know how to analyze. In that case we stop there and
// we assume that they can mutate the underlying expression.
// we assume that they can modify the expression.

struct StackEntry {
StackEntry(const Expr *E, int Indirections)
Expand All @@ -90,7 +199,7 @@ AST_MATCHER_P(DeclRefExpr, doesNotMutateObject, int, Indirections) {
assert(Ty->isPointerType());
Ty = Ty->getPointeeType().getCanonicalType();
}
if (Ty.isConstQualified())
if (Ty->isVoidType() || Ty.isConstQualified())
continue;

// Otherwise we have to look at the parents to see how the expression is
Expand Down Expand Up @@ -159,11 +268,56 @@ AST_MATCHER_P(DeclRefExpr, doesNotMutateObject, int, Indirections) {
// The method call cannot mutate our variable.
continue;
}
if (isLikelyShallowConst(*Method)) {
// We still have to check that the object is not modified through
// the method's return value (C).
const auto MemberParents = Ctx.getParents(*Member);
assert(MemberParents.size() == 1);
const auto *Call = MemberParents[0].get<CallExpr>();
// If `o` is an object of class type and `f` is a member function,
// then `o.f` has to be used as part of a call expression.
assert(Call != nullptr && "member function has to be called");
Stack.emplace_back(
Call,
Method->getReturnType().getCanonicalType()->isPointerType()
? 1
: 0);
continue;
}
return false;
}
Stack.emplace_back(Member, 0);
continue;
}
if (const auto *const OpCall = dyn_cast<CXXOperatorCallExpr>(P)) {
// Operator calls have function call syntax. The `*this` parameter
// is the first parameter.
if (OpCall->getNumArgs() == 0 || OpCall->getArg(0) != Entry.E) {
return false;
}
const auto *const Method =
dyn_cast<CXXMethodDecl>(OpCall->getDirectCallee());

if (Method == nullptr) {
// This is not a member operator. Typically, a friend operator. These
// are handled like function calls.
return false;
}

if (Method->isConst() || Method->isStatic()) {
continue;
}
if (isLikelyShallowConst(*Method)) {
// We still have to check that the object is not modified through
// the operator's return value (C).
Stack.emplace_back(
OpCall,
Method->getReturnType().getCanonicalType()->isPointerType() ? 1
: 0);
continue;
}
return false;
}

if (const auto *const Op = dyn_cast<UnaryOperator>(P)) {
switch (Op->getOpcode()) {
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/FindSymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ class DocumentOutline {
if (!MacroName.isValid() || !MacroName.isFileID())
continue;
// All conditions satisfied, add the macro.
if (auto *Tok = AST.getTokens().spelledTokenAt(MacroName))
if (auto *Tok = AST.getTokens().spelledTokenContaining(MacroName))
CurParent = &CurParent->inMacro(
*Tok, SM, AST.getTokens().expansionStartingAt(Tok));
}
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/IncludeCleaner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ collectMacroReferences(ParsedAST &AST) {
for (const auto &[_, Refs] : AST.getMacros().MacroRefs) {
for (const auto &Ref : Refs) {
auto Loc = SM.getComposedLoc(SM.getMainFileID(), Ref.StartOffset);
const auto *Tok = AST.getTokens().spelledTokenAt(Loc);
const auto *Tok = AST.getTokens().spelledTokenContaining(Loc);
if (!Tok)
continue;
auto Macro = locateMacroAt(*Tok, PP);
Expand Down
11 changes: 5 additions & 6 deletions clang-tools-extra/clangd/SemanticHighlighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,11 +447,10 @@ class HighlightingsBuilder {
if (!RLoc.isValid())
return;

const auto *RTok = TB.spelledTokenAt(RLoc);
// Handle `>>`. RLoc is always pointing at the right location, just change
// the end to be offset by 1.
// We'll either point at the beginning of `>>`, hence get a proper spelled
// or point in the middle of `>>` hence get no spelled tok.
const auto *RTok = TB.spelledTokenContaining(RLoc);
// Handle `>>`. RLoc is either part of `>>` or a spelled token on its own
// `>`. If it's the former, slice to have length of 1, if latter use the
// token as-is.
if (!RTok || RTok->kind() == tok::greatergreater) {
Position Begin = sourceLocToPosition(SourceMgr, RLoc);
Position End = sourceLocToPosition(SourceMgr, RLoc.getLocWithOffset(1));
Expand Down Expand Up @@ -577,7 +576,7 @@ class HighlightingsBuilder {
return std::nullopt;
// We might have offsets in the main file that don't correspond to any
// spelled tokens.
const auto *Tok = TB.spelledTokenAt(Loc);
const auto *Tok = TB.spelledTokenContaining(Loc);
if (!Tok)
return std::nullopt;
return halfOpenToRange(SourceMgr,
Expand Down
9 changes: 5 additions & 4 deletions clang-tools-extra/clangd/XRefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
if (Inc.Resolved.empty())
continue;
auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
const auto *HashTok = AST.getTokens().spelledTokenAt(HashLoc);
const auto *HashTok = AST.getTokens().spelledTokenContaining(HashLoc);
assert(HashTok && "got inclusion at wrong offset");
const auto *IncludeTok = std::next(HashTok);
const auto *FileTok = std::next(IncludeTok);
Expand Down Expand Up @@ -938,7 +938,7 @@ class ReferenceFinder : public index::IndexDataConsumer {
CollectorOpts.CollectMainFileSymbols = true;
for (SourceLocation L : Locs) {
L = SM.getFileLoc(L);
if (const auto *Tok = TB.spelledTokenAt(L))
if (const auto *Tok = TB.spelledTokenContaining(L))
References.push_back(
{*Tok, Roles,
SymbolCollector::getRefContainer(ASTNode.Parent, CollectorOpts)});
Expand Down Expand Up @@ -1216,7 +1216,7 @@ DocumentHighlight toHighlight(const ReferenceFinder::Reference &Ref,
std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
const syntax::TokenBuffer &TB) {
Loc = TB.sourceManager().getFileLoc(Loc);
if (const auto *Tok = TB.spelledTokenAt(Loc)) {
if (const auto *Tok = TB.spelledTokenContaining(Loc)) {
DocumentHighlight Result;
Result.range = halfOpenToRange(
TB.sourceManager(),
Expand Down Expand Up @@ -1353,7 +1353,8 @@ maybeFindIncludeReferences(ParsedAST &AST, Position Pos,
Loc = SM.getIncludeLoc(SM.getFileID(Loc));

ReferencesResult::Reference Result;
const auto *Token = AST.getTokens().spelledTokenAt(Loc);
const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
assert(Token && "references expected token here");
Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
sourceLocToPosition(SM, Token->endLocation())};
Result.Loc.uri = URIMainFile;
Expand Down
6 changes: 5 additions & 1 deletion clang-tools-extra/clangd/index/remote/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ if (CLANGD_ENABLE_REMOTE)
clangdRemoteIndexProto
clangdRemoteIndexServiceProto
clangdRemoteMarshalling
clangBasic
clangDaemon
clangdSupport

Expand All @@ -35,6 +34,11 @@ if (CLANGD_ENABLE_REMOTE)
clangdRemoteIndexServiceProto
)

clang_target_link_libraries(clangdRemoteIndex
PRIVATE
clangBasic
)

add_subdirectory(marshalling)
add_subdirectory(server)
add_subdirectory(monitor)
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/refactor/Rename.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ std::vector<SymbolRange> collectRenameIdentifierRanges(
clangd::Range tokenRangeForLoc(ParsedAST &AST, SourceLocation TokLoc,
const SourceManager &SM,
const LangOptions &LangOpts) {
const auto *Token = AST.getTokens().spelledTokenAt(TokLoc);
const auto *Token = AST.getTokens().spelledTokenContaining(TokLoc);
assert(Token && "rename expects spelled tokens");
clangd::Range Result;
Result.start = sourceLocToPosition(SM, Token->location());
Expand Down
11 changes: 6 additions & 5 deletions clang-tools-extra/clangd/unittests/PreambleTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ TEST(PreamblePatchTest, LocateMacroAtWorks) {
ASSERT_TRUE(AST);

const auto &SM = AST->getSourceManager();
auto *MacroTok = AST->getTokens().spelledTokenAt(
auto *MacroTok = AST->getTokens().spelledTokenContaining(
SM.getComposedLoc(SM.getMainFileID(), Modified.point("use")));
ASSERT_TRUE(MacroTok);

Expand All @@ -441,7 +441,7 @@ TEST(PreamblePatchTest, LocateMacroAtDeletion) {
ASSERT_TRUE(AST);

const auto &SM = AST->getSourceManager();
auto *MacroTok = AST->getTokens().spelledTokenAt(
auto *MacroTok = AST->getTokens().spelledTokenContaining(
SM.getComposedLoc(SM.getMainFileID(), Modified.point()));
ASSERT_TRUE(MacroTok);

Expand Down Expand Up @@ -512,9 +512,10 @@ TEST(PreamblePatchTest, RefsToMacros) {
ExpectedLocations.push_back(referenceRangeIs(R));

for (const auto &P : Modified.points()) {
auto *MacroTok = AST->getTokens().spelledTokenAt(SM.getComposedLoc(
SM.getMainFileID(),
llvm::cantFail(positionToOffset(Modified.code(), P))));
auto *MacroTok =
AST->getTokens().spelledTokenContaining(SM.getComposedLoc(
SM.getMainFileID(),
llvm::cantFail(positionToOffset(Modified.code(), P))));
ASSERT_TRUE(MacroTok);
EXPECT_THAT(findReferences(*AST, P, 0).References,
testing::ElementsAreArray(ExpectedLocations));
Expand Down
16 changes: 15 additions & 1 deletion clang-tools-extra/clangd/unittests/XRefsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2173,6 +2173,11 @@ TEST(FindReferences, WithinAST) {
using $def[[MyTypeD^ef]] = int;
enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
)cpp",
// UDL
R"cpp(
bool $decl[[operator]]"" _u^dl(unsigned long long value);
bool x = $(x)[[1_udl]];
)cpp",
};
for (const char *Test : Tests)
checkFindRefs(Test);
Expand Down Expand Up @@ -2358,7 +2363,13 @@ TEST(FindReferences, UsedSymbolsFromInclude) {

R"cpp([[#in^clude <vector>]]
std::[[vector]]<int> vec;
)cpp"};
)cpp",

R"cpp(
[[#include ^"udl_header.h"]]
auto x = [[1_b]];
)cpp",
};
for (const char *Test : Tests) {
Annotations T(Test);
auto TU = TestTU::withCode(T.code());
Expand All @@ -2375,6 +2386,9 @@ TEST(FindReferences, UsedSymbolsFromInclude) {
class vector{};
}
)cpp");
TU.AdditionalFiles["udl_header.h"] = guard(R"cpp(
bool operator"" _b(unsigned long long value);
)cpp");
TU.ExtraArgs.push_back("-isystem" + testPath("system"));

auto AST = TU.build();
Expand Down
17 changes: 15 additions & 2 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ New checks
to reading out-of-bounds data due to inadequate or incorrect string null
termination.

- New :doc:`misc-use-internal-linkage
<clang-tidy/checks/misc/use-internal-linkage>` check.

Detects variables and functions that can be marked as static or moved into
an anonymous namespace to enforce internal linkage.

- New :doc:`modernize-min-max-use-initializer-list
<clang-tidy/checks/modernize/min-max-use-initializer-list>` check.

Expand Down Expand Up @@ -218,6 +224,10 @@ Changes in existing checks
check by ignoring ``__func__`` macro in lambda captures, initializers of
default parameters and nested function declarations.

- Improved :doc:`bugprone-multi-level-implicit-pointer-conversion
<clang-tidy/checks/bugprone/multi-level-implicit-pointer-conversion>` check
by ignoring implicit pointer conversions that are part of a cast expression.

- Improved :doc:`bugprone-non-zero-enum-to-bool-conversion
<clang-tidy/checks/bugprone/non-zero-enum-to-bool-conversion>` check by
eliminating false positives resulting from direct usage of bitwise operators
Expand Down Expand Up @@ -366,8 +376,10 @@ Changes in existing checks
- Improved :doc:`performance-unnecessary-copy-initialization
<clang-tidy/checks/performance/unnecessary-copy-initialization>` check by
detecting more cases of constant access. In particular, pointers can be
analyzed, se the check now handles the common patterns
analyzed, so the check now handles the common patterns
`const auto e = (*vector_ptr)[i]` and `const auto e = vector_ptr->at(i);`.
Calls to mutable function where there exists a `const` overload are also
handled.

- Improved :doc:`readability-avoid-return-with-void-value
<clang-tidy/checks/readability/avoid-return-with-void-value>` check by adding
Expand Down Expand Up @@ -402,7 +414,8 @@ Changes in existing checks
valid fix suggestions for ``static_cast`` without a preceding space and
fixed problem with duplicate parentheses in double implicit casts. Corrected
the fix suggestions for C23 and later by using C-style casts instead of
``static_cast``.
``static_cast``. Fixed false positives in C++20 spaceship operator by ignoring
casts in implicit and defaulted functions.

- Improved :doc:`readability-redundant-inline-specifier
<clang-tidy/checks/readability/redundant-inline-specifier>` check to properly
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.. title:: clang-tidy - clang-analyzer-cplusplus.ArrayDelete
.. meta::
:http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-arraydelete

clang-analyzer-cplusplus.ArrayDelete
====================================

Reports destructions of arrays of polymorphic objects that are destructed as
their base class.

The `clang-analyzer-cplusplus.ArrayDelete` check is an alias, please see
`Clang Static Analyzer Available Checkers
<https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-arraydelete>`_
for more information.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.. title:: clang-tidy - clang-analyzer-security.SetgidSetuidOrder

clang-analyzer-security.SetgidSetuidOrder
=========================================

Warn on possible reversed order of 'setgid(getgid()))' and 'setuid(getuid())'
(CERT: POS36-C).

The clang-analyzer-security.SetgidSetuidOrder check is an alias of
Clang Static Analyzer security.SetgidSetuidOrder.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.. title:: clang-tidy - clang-analyzer-unix.Stream
.. meta::
:http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#unix-stream

clang-analyzer-unix.Stream
==========================

Check stream handling functions.

The `clang-analyzer-unix.Stream` check is an alias, please see
`Clang Static Analyzer Available Checkers
<https://clang.llvm.org/docs/analyzer/checkers.html#unix-stream>`_
for more information.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def get_checkers(checkers_td, checkers_rst):
parent_package_ = package["ParentPackage"]
hidden = (checker["Hidden"] != 0) or (package["Hidden"] != 0)

while parent_package_ != None:
while parent_package_ is not None:
parent_package = table_entries[parent_package_["def"]]
checker_package_prefix = (
parent_package["PackageName"] + "." + checker_package_prefix
Expand All @@ -59,7 +59,7 @@ def get_checkers(checkers_td, checkers_rst):
"clang-analyzer-" + checker_package_prefix + "." + checker_name
)
anchor_url = re.sub(
"\.", "-", checker_package_prefix + "." + checker_name
r"\.", "-", checker_package_prefix + "." + checker_name
).lower()

if not hidden and "alpha" not in full_package_name.lower():
Expand Down Expand Up @@ -130,7 +130,7 @@ def generate_documentation(checker, has_documentation):
def update_documentation_list(checkers):
with open(os.path.join(__location__, "list.rst"), "r+") as f:
f_text = f.read()
check_text = f_text.split(".. csv-table:: Aliases..\n")[1]
check_text = f_text.split(':header: "Name", "Redirect", "Offers fixes"\n')[1]
checks = [x for x in check_text.split("\n") if ":header:" not in x and x]
old_check_text = "\n".join(checks)
checks = [x for x in checks if "clang-analyzer-" not in x]
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ Clang-Tidy Checks
:doc:`misc-unused-parameters <misc/unused-parameters>`, "Yes"
:doc:`misc-unused-using-decls <misc/unused-using-decls>`, "Yes"
:doc:`misc-use-anonymous-namespace <misc/use-anonymous-namespace>`,
:doc:`misc-use-internal-linkage <misc/use-internal-linkage>`,
:doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes"
:doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
:doc:`modernize-concat-nested-namespaces <modernize/concat-nested-namespaces>`, "Yes"
Expand Down Expand Up @@ -442,6 +443,7 @@ Check aliases
:doc:`clang-analyzer-core.uninitialized.CapturedBlockVariable <clang-analyzer/core.uninitialized.CapturedBlockVariable>`, `Clang Static Analyzer core.uninitialized.CapturedBlockVariable <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-capturedblockvariable>`_,
:doc:`clang-analyzer-core.uninitialized.NewArraySize <clang-analyzer/core.uninitialized.NewArraySize>`, `Clang Static Analyzer core.uninitialized.NewArraySize <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-newarraysize>`_,
:doc:`clang-analyzer-core.uninitialized.UndefReturn <clang-analyzer/core.uninitialized.UndefReturn>`, `Clang Static Analyzer core.uninitialized.UndefReturn <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-undefreturn>`_,
:doc:`clang-analyzer-cplusplus.ArrayDelete <clang-analyzer/cplusplus.ArrayDelete>`, `Clang Static Analyzer cplusplus.ArrayDelete <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-arraydelete>`_,
:doc:`clang-analyzer-cplusplus.InnerPointer <clang-analyzer/cplusplus.InnerPointer>`, `Clang Static Analyzer cplusplus.InnerPointer <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-innerpointer>`_,
:doc:`clang-analyzer-cplusplus.Move <clang-analyzer/cplusplus.Move>`, Clang Static Analyzer cplusplus.Move,
:doc:`clang-analyzer-cplusplus.NewDelete <clang-analyzer/cplusplus.NewDelete>`, `Clang Static Analyzer cplusplus.NewDelete <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-newdelete>`_,
Expand Down Expand Up @@ -496,6 +498,7 @@ Check aliases
:doc:`clang-analyzer-osx.coreFoundation.containers.OutOfBounds <clang-analyzer/osx.coreFoundation.containers.OutOfBounds>`, `Clang Static Analyzer osx.coreFoundation.containers.OutOfBounds <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-outofbounds>`_,
:doc:`clang-analyzer-osx.coreFoundation.containers.PointerSizedValues <clang-analyzer/osx.coreFoundation.containers.PointerSizedValues>`, `Clang Static Analyzer osx.coreFoundation.containers.PointerSizedValues <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-pointersizedvalues>`_,
:doc:`clang-analyzer-security.FloatLoopCounter <clang-analyzer/security.FloatLoopCounter>`, `Clang Static Analyzer security.FloatLoopCounter <https://clang.llvm.org/docs/analyzer/checkers.html#security-floatloopcounter>`_,
:doc:`clang-analyzer-security.SetgidSetuidOrder <clang-analyzer/security.SetgidSetuidOrder>`, Clang Static Analyzer security.SetgidSetuidOrder,
:doc:`clang-analyzer-security.cert.env.InvalidPtr <clang-analyzer/security.cert.env.InvalidPtr>`, `Clang Static Analyzer security.cert.env.InvalidPtr <https://clang.llvm.org/docs/analyzer/checkers.html#security-cert-env-invalidptr>`_,
:doc:`clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling <clang-analyzer/security.insecureAPI.DeprecatedOrUnsafeBufferHandling>`, `Clang Static Analyzer security.insecureAPI.DeprecatedOrUnsafeBufferHandling <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-deprecatedorunsafebufferhandling>`_,
:doc:`clang-analyzer-security.insecureAPI.UncheckedReturn <clang-analyzer/security.insecureAPI.UncheckedReturn>`, `Clang Static Analyzer security.insecureAPI.UncheckedReturn <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-uncheckedreturn>`_,
Expand All @@ -516,6 +519,7 @@ Check aliases
:doc:`clang-analyzer-unix.MallocSizeof <clang-analyzer/unix.MallocSizeof>`, `Clang Static Analyzer unix.MallocSizeof <https://clang.llvm.org/docs/analyzer/checkers.html#unix-mallocsizeof>`_,
:doc:`clang-analyzer-unix.MismatchedDeallocator <clang-analyzer/unix.MismatchedDeallocator>`, `Clang Static Analyzer unix.MismatchedDeallocator <https://clang.llvm.org/docs/analyzer/checkers.html#unix-mismatcheddeallocator>`_,
:doc:`clang-analyzer-unix.StdCLibraryFunctions <clang-analyzer/unix.StdCLibraryFunctions>`, `Clang Static Analyzer unix.StdCLibraryFunctions <https://clang.llvm.org/docs/analyzer/checkers.html#unix-stdclibraryfunctions>`_,
:doc:`clang-analyzer-unix.Stream <clang-analyzer/unix.Stream>`, `Clang Static Analyzer unix.Stream <https://clang.llvm.org/docs/analyzer/checkers.html#unix-stream>`_,
:doc:`clang-analyzer-unix.Vfork <clang-analyzer/unix.Vfork>`, `Clang Static Analyzer unix.Vfork <https://clang.llvm.org/docs/analyzer/checkers.html#unix-vfork>`_,
:doc:`clang-analyzer-unix.cstring.BadSizeArg <clang-analyzer/unix.cstring.BadSizeArg>`, `Clang Static Analyzer unix.cstring.BadSizeArg <https://clang.llvm.org/docs/analyzer/checkers.html#unix-cstring-badsizearg>`_,
:doc:`clang-analyzer-unix.cstring.NullArg <clang-analyzer/unix.cstring.NullArg>`, `Clang Static Analyzer unix.cstring.NullArg <https://clang.llvm.org/docs/analyzer/checkers.html#unix-cstring-nullarg>`_,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.. title:: clang-tidy - misc-use-internal-linkage

misc-use-internal-linkage
=========================

Detects variables and functions that can be marked as static or moved into
an anonymous namespace to enforce internal linkage.

Static functions and variables are scoped to a single file. Marking functions
and variables as static helps to better remove dead code. In addition, it gives
the compiler more information and allows for more aggressive optimizations.

Example:

.. code-block:: c++

int v1; // can be marked as static

void fn1(); // can be marked as static

namespace {
// already in anonymous namespace
int v2;
void fn2();
}
// already declared as extern
extern int v2;
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ declaration of ``S``.

Even when compiling in a language version older than C++20, depending on your
compiler, designated initializers are potentially supported. Therefore, the
check is not restricted to C++20 and newer versions. Check out the options
check is by default restricted to C99/C++20 and above. Check out the options
``-Wc99-designator`` to get support for mixed designators in initializer list in
C and ``-Wc++20-designator`` for support of designated initializers in older C++
language modes.
Expand All @@ -60,3 +60,13 @@ Options
The value `true` specifies that only Plain Old Data (POD) types shall be
checked. This makes the check applicable to even older C++ standards. The
default value is `false`.

.. option:: StrictCStandardCompliance

When set to `false`, the check will not restrict itself to C99 and above.
The default value is `true`.

.. option:: StrictCppStandardCompliance

When set to `false`, the check will not restrict itself to C++20 and above.
The default value is `true`.
8 changes: 6 additions & 2 deletions clang-tools-extra/pseudo/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ add_clang_library(clangPseudo
Token.cpp

LINK_LIBS
clangBasic
clangLex
clangPseudoGrammar

DEPENDS
Expand All @@ -25,3 +23,9 @@ add_clang_library(clangPseudo
target_include_directories(clangPseudo INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
)

clang_target_link_libraries(clangPseudo
PRIVATE
clangBasic
clangLex
)
6 changes: 5 additions & 1 deletion clang-tools-extra/pseudo/lib/cxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ add_clang_library(clangPseudoCXX
cxx_gen

LINK_LIBS
clangBasic
clangPseudo
clangPseudoGrammar
)

clang_target_link_libraries(clangPseudoCXX
PRIVATE
clangBasic
)
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,15 @@ void test()

takeSecondLevelVoidPtr(getSecondLevelVoidPtr());
}

namespace PR93959 {
void free(void*);

void test() {
char **p = nullptr;
free(p);
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: multilevel pointer conversion from 'char **' to 'void *', please use explicit cast [bugprone-multi-level-implicit-pointer-conversion]
free((void *)p);
free(static_cast<void *>(p));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

void func_header();

#include "func_h.inc"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
void func_cpp_inc();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
void func_h_inc();
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

extern int gloabl_header;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// RUN: %check_clang_tidy %s misc-use-internal-linkage %t -- -- -I%S/Inputs/use-internal-linkage

#include "func.h"

void func() {}
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'func'

template<class T>
void func_template() {}
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'func_template'

void func_cpp_inc();
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'func_cpp_inc'

#include "func_cpp.inc"

void func_h_inc();

struct S {
void method();
};
void S::method() {}

void func_header();
extern void func_extern();
static void func_static();
namespace {
void func_anonymous_ns();
} // namespace

int main(int argc, const char*argv[]) {}

extern "C" {
void func_extern_c_1() {}
}

extern "C" void func_extern_c_2() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// RUN: %check_clang_tidy %s misc-use-internal-linkage %t -- -- -I%S/Inputs/use-internal-linkage

#include "var.h"

int global;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: variable 'global'

template<class T>
T global_template;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: variable 'global_template'

int gloabl_header;

extern int global_extern;

static int global_static;

namespace {
static int global_anonymous_ns;
namespace NS {
static int global_anonymous_ns;
}
}

static void f(int para) {
int local;
static int local_static;
}

struct S {
int m1;
static int m2;
};
int S::m2;

extern "C" {
int global_in_extern_c_1;
}

extern "C" int global_in_extern_c_2;
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// RUN: %check_clang_tidy -std=c++17 %s modernize-use-designated-initializers %t \
// RUN: %check_clang_tidy -std=c++20 %s modernize-use-designated-initializers %t \
// RUN: -- \
// RUN: -- -fno-delayed-template-parsing
// RUN: %check_clang_tidy -check-suffixes=,SINGLE-ELEMENT -std=c++17 %s modernize-use-designated-initializers %t \
// RUN: %check_clang_tidy -check-suffixes=,SINGLE-ELEMENT -std=c++20 %s modernize-use-designated-initializers %t \
// RUN: -- -config="{CheckOptions: {modernize-use-designated-initializers.IgnoreSingleElementAggregates: false}}" \
// RUN: -- -fno-delayed-template-parsing
// RUN: %check_clang_tidy -check-suffixes=POD -std=c++17 %s modernize-use-designated-initializers %t \
// RUN: %check_clang_tidy -check-suffixes=POD -std=c++20 %s modernize-use-designated-initializers %t \
// RUN: -- -config="{CheckOptions: {modernize-use-designated-initializers.RestrictToPODTypes: true}}" \
// RUN: -- -fno-delayed-template-parsing
// RUN: %check_clang_tidy -check-suffixes=,MACROS -std=c++17 %s modernize-use-designated-initializers %t \
// RUN: %check_clang_tidy -check-suffixes=,MACROS -std=c++20 %s modernize-use-designated-initializers %t \
// RUN: -- -config="{CheckOptions: {modernize-use-designated-initializers.IgnoreMacros: false}}" \
// RUN: -- -fno-delayed-template-parsing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ struct ExpensiveToCopyType {

template <typename T>
struct Container {
using reference = T&;
using const_reference = const T&;

bool empty() const;
const T& operator[](int) const;
const T& operator[](int);
Expand All @@ -42,8 +45,8 @@ struct Container {
void nonConstMethod();
bool constMethod() const;

const T& at(int) const;
T& at(int);
reference at(int) const;
const_reference at(int);

};

Expand Down Expand Up @@ -207,6 +210,28 @@ void PositiveOperatorCallConstValueParam(const Container<ExpensiveToCopyType> C)
VarCopyConstructed.constMethod();
}

void PositiveOperatorValueParam(Container<ExpensiveToCopyType> C) {
const auto AutoAssigned = C[42];
// CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
// CHECK-FIXES: const auto& AutoAssigned = C[42];
AutoAssigned.constMethod();

const auto AutoCopyConstructed(C[42]);
// CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
// CHECK-FIXES: const auto& AutoCopyConstructed(C[42]);
AutoCopyConstructed.constMethod();

const ExpensiveToCopyType VarAssigned = C.at(42);
// CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
// CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C.at(42);
VarAssigned.constMethod();

const ExpensiveToCopyType VarCopyConstructed(C.at(42));
// CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
// CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C.at(42));
VarCopyConstructed.constMethod();
}

void PositiveOperatorCallConstValueParamAlias(const ExpensiveToCopyContainerAlias C) {
const auto AutoAssigned = C[42];
// CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// RUN: %check_clang_tidy -std=c++20 %s readability-implicit-bool-conversion %t

namespace std {
struct strong_ordering {
int n;
constexpr operator int() const { return n; }
static const strong_ordering equal, greater, less;
};
constexpr strong_ordering strong_ordering::equal = {0};
constexpr strong_ordering strong_ordering::greater = {1};
constexpr strong_ordering strong_ordering::less = {-1};
} // namespace std

namespace PR93409 {
struct X
{
auto operator<=>(const X&) const = default;
bool m_b;
};

struct Y
{
auto operator<=>(const Y&) const = default;
X m_x;
};

bool compare(const Y& y1, const Y& y2)
{
return y1 == y2 || y1 < y2 || y1 > y2;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,20 @@ void f(){
//CHECK-MESSAGES: :[[@LINE+1]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int v = FUN5(0 + 1);
}

namespace PR92516 {
void f(int i) {
int j, k;
for (j = i + 1, k = 0; j < 1; ++j) {}
}

void f2(int i) {
int j;
for (j = i + 1; j < 1; ++j) {}
}

void f3(int i) {
int j;
for (j = i + 1, 2; j < 1; ++j) {}
}
}
48 changes: 43 additions & 5 deletions clang-tools-extra/unittests/clang-tidy/DeclRefExprUtilsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ template <int Indirections> void RunTest(StringRef Snippet) {
StringRef CommonCode = R"(
struct ConstTag{};
struct NonConstTag{};
struct Tag1{};
struct S {
void constMethod() const;
Expand All @@ -59,6 +60,13 @@ template <int Indirections> void RunTest(StringRef Snippet) {
void operator[](int);
void operator[](int) const;
int& at(int);
const int& at(int) const;
const int& at(Tag1);
int& weird_overload();
const double& weird_overload() const;
bool operator==(const S&) const;
int int_member;
Expand Down Expand Up @@ -161,9 +169,11 @@ TEST(ConstReferenceDeclRefExprsTest, ConstRefVar) {
useIntConstRef(/*const*/target.int_member);
useIntPtr(/*const*/target.ptr_member);
useIntConstPtr(&/*const*/target.int_member);
(void)/*const*/target.at(3);
const S& const_target_ref = /*const*/target;
const S* const_target_ptr = &/*const*/target;
(void)/*const*/target.at(3);
}
)");
}
Expand All @@ -187,7 +197,7 @@ TEST(ConstReferenceDeclRefExprsTest, ValueVar) {
/*const*/target.staticMethod();
target.nonConstMethod();
/*const*/target(ConstTag{});
target[42];
/*const*/target[42];
/*const*/target(ConstTag{});
target(NonConstTag{});
useRef(target);
Expand All @@ -211,6 +221,14 @@ TEST(ConstReferenceDeclRefExprsTest, ValueVar) {
const S& const_target_ref = /*const*/target;
const S* const_target_ptr = &/*const*/target;
S* target_ptr = &target;
(void)/*const*/target.at(3);
++target.at(3);
const int civ = /*const*/target.at(3);
const int& cir = /*const*/target.at(3);
int& ir = target.at(3);
target.at(Tag1{});
target.weird_overload();
}
)");
}
Expand All @@ -227,7 +245,7 @@ TEST(ConstReferenceDeclRefExprsTest, RefVar) {
/*const*/target.staticMethod();
target.nonConstMethod();
/*const*/target(ConstTag{});
target[42];
/*const*/target[42];
useConstRef((/*const*/target));
(/*const*/target).constMethod();
(void)(/*const*/target == /*const*/target);
Expand All @@ -249,6 +267,14 @@ TEST(ConstReferenceDeclRefExprsTest, RefVar) {
const S& const_target_ref = /*const*/target;
const S* const_target_ptr = &/*const*/target;
S* target_ptr = &target;
(void)/*const*/target.at(3);
++target.at(3);
const int civ = /*const*/target.at(3);
const int& cir = /*const*/target.at(3);
int& ir = target.at(3);
target.at(Tag1{});
target.weird_overload();
}
)");
}
Expand All @@ -266,8 +292,8 @@ TEST(ConstReferenceDeclRefExprsTest, PtrVar) {
/*const*/target->staticMethod();
target->nonConstMethod();
(*/*const*/target)(ConstTag{});
(*target)[42];
target->operator[](42);
(*/*const*/target)[42];
/*const*/target->operator[](42);
useConstRef((*/*const*/target));
(/*const*/target)->constMethod();
(void)(*/*const*/target == */*const*/target);
Expand All @@ -284,7 +310,15 @@ TEST(ConstReferenceDeclRefExprsTest, PtrVar) {
const S& const_target_ref = */*const*/target;
const S* const_target_ptr = /*const*/target;
S* target_ptr = target; // FIXME: we could chect const usage of `target_ptr`.
S* target_ptr = target; // FIXME: we could chect const usage of `target_ptr`
(void)/*const*/target->at(3);
++target->at(3);
const int civ = /*const*/target->at(3);
const int& cir = /*const*/target->at(3);
int& ir = target->at(3);
target->at(Tag1{});
target->weird_overload();
}
)");
}
Expand Down Expand Up @@ -319,6 +353,10 @@ TEST(ConstReferenceDeclRefExprsTest, ConstPtrVar) {
const S& const_target_ref = */*const*/target;
const S* const_target_ptr = /*const*/target;
(void)/*const*/target->at(3);
const int civ = /*const*/target->at(3);
const int& cir = /*const*/target->at(3);
}
)");
}
Expand Down
22 changes: 9 additions & 13 deletions clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,9 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wno-long-long")
endif ()

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types" )
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types" )
endif ()
endif ()

# Determine HOST_LINK_VERSION on Darwin.
Expand Down Expand Up @@ -848,23 +850,17 @@ if (CLANG_ENABLE_BOOTSTRAP)
set(CLANG_BOOTSTRAP_TARGETS check-llvm check-clang check-all)
endif()
foreach(target ${CLANG_BOOTSTRAP_TARGETS})
# Install targets have side effects, so we always want to execute them.
# "install" is reserved by CMake and can't be used as a step name for
# ExternalProject_Add_Step, so we can match against "^install-" instead of
# "^install" to get a tighter match. CMake's installation scripts already
# skip up-to-date files, so there's no behavior change if you install to the
# same destination multiple times.
if(target MATCHES "^install-")
set(step_always ON)
else()
set(step_always OFF)
endif()

ExternalProject_Add_Step(${NEXT_CLANG_STAGE} ${target}
COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target ${target}
COMMENT "Performing ${target} for '${NEXT_CLANG_STAGE}'"
DEPENDEES configure
ALWAYS ${step_always}
# We need to set ALWAYS to ON here, otherwise these targets won't be
# built on a second invocation of ninja. The targets have their own
# logic to determine if they should build or not so setting ALWAYS ON
# here does not mean the targets will always rebuild it just means that
# they will check their dependenices and see if they need to be built.
ALWAYS ON
EXCLUDE_FROM_MAIN ON
USES_TERMINAL 1
)
Expand Down
45 changes: 31 additions & 14 deletions clang/cmake/caches/CrossWinToARMLinux.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,23 @@
# on Windows platform.
#
# NOTE: the build requires a development ARM Linux root filesystem to use
# proper target platform depended library and header files:
# - create <full-path-to-clang-configs> directory and put the clang configuration
# file named <TOOLCHAIN_TARGET_TRIPLE>.cfg into it.
# - add the `--sysroot=<path-to-develop-arm-linux-root-fs>` argument into
# this configuration file.
# - add other necessary target depended clang arguments there,
# such as '-mcpu=cortex-a78' & etc.
# proper target platform depended library and header files.
#
# The build generates a proper clang configuration file with stored
# --sysroot argument for specified target triple. Also it is possible
# to specify configuration path via CMake arguments, such as
# -DCLANG_CONFIG_FILE_USER_DIR=<full-path-to-clang-configs>
# and/or
# -DCLANG_CONFIG_FILE_SYSTEM_DIR=<full-path-to-clang-configs>
#
# See more details here: https://clang.llvm.org/docs/UsersManual.html#configuration-files
#
# Configure:
# cmake -G Ninja ^
# -DTOOLCHAIN_TARGET_TRIPLE=aarch64-unknown-linux-gnu ^
# -DTOOLCHAIN_TARGET_SYSROOTFS=<path-to-develop-arm-linux-root-fs> ^
# -DTOOLCHAIN_SHARED_LIBS=OFF ^
# -DCMAKE_INSTALL_PREFIX=../install ^
# -DCLANG_CONFIG_FILE_USER_DIR=<full-path-to-clang-configs> ^
# -DCMAKE_CXX_FLAGS="-D__OPTIMIZE__" ^
# -DREMOTE_TEST_HOST="<hostname>" ^
# -DREMOTE_TEST_USER="<ssh_user_name>" ^
Expand Down Expand Up @@ -81,6 +83,20 @@ endif()

message(STATUS "Toolchain target triple: ${TOOLCHAIN_TARGET_TRIPLE}")

if (DEFINED TOOLCHAIN_TARGET_SYSROOTFS)
message(STATUS "Toolchain target sysroot: ${TOOLCHAIN_TARGET_SYSROOTFS}")
# Store the --sysroot argument for the compiler-rt test flags.
set(sysroot_flags --sysroot='${TOOLCHAIN_TARGET_SYSROOTFS}')
# Generate the clang configuration file for the specified target triple
# and store --sysroot in this file.
file(WRITE "${CMAKE_BINARY_DIR}/bin/${TOOLCHAIN_TARGET_TRIPLE}.cfg" ${sysroot_flags})
endif()

# Build the shared libraries for libc++/libc++abi/libunwind.
if (NOT DEFINED TOOLCHAIN_SHARED_LIBS)
set(TOOLCHAIN_SHARED_LIBS OFF)
endif()

if (NOT DEFINED LLVM_TARGETS_TO_BUILD)
if ("${TOOLCHAIN_TARGET_TRIPLE}" MATCHES "^(armv|arm32)+")
set(LLVM_TARGETS_TO_BUILD "ARM" CACHE STRING "")
Expand Down Expand Up @@ -183,20 +199,21 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_CAN_EXECUTE_TESTS

set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_USE_BUILTINS_LIBRARY ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_CXX_LIBRARY libcxx CACHE STRING "")
# Tell Clang to seach C++ headers alongside with the just-built binaries for the C++ compiler-rt tests.
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_TEST_COMPILER_CFLAGS "--stdlib=libc++" CACHE STRING "")

# The compiler-rt tests disable the clang configuration files during the execution by setting CLANG_NO_DEFAULT_CONFIG=1
# and drops out the --sysroot from there. Provide it explicity via the test flags here if target sysroot has been specified.
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_TEST_COMPILER_CFLAGS "--stdlib=libc++ ${sysroot_flags}" CACHE STRING "")

set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_ENABLE_SHARED ${TOOLCHAIN_SHARED_LIBS} CACHE BOOL "")

set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_STATIC_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_SHARED ${TOOLCHAIN_SHARED_LIBS} CACHE BOOL "")

set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_SHARED ${TOOLCHAIN_SHARED_LIBS} CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ABI_VERSION ${LIBCXX_ABI_VERSION} CACHE STRING "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_CXX_ABI "libcxxabi" CACHE STRING "") #!!!
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "")
Expand Down
4 changes: 3 additions & 1 deletion clang/cmake/caches/Release.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ endfunction()
#
# cmake -D LLVM_RELEASE_ENABLE_PGO=ON -C Release.cmake
set(LLVM_RELEASE_ENABLE_LTO THIN CACHE STRING "")
set(LLVM_RELEASE_ENABLE_PGO OFF CACHE BOOL "")
set(LLVM_RELEASE_ENABLE_PGO ON CACHE BOOL "")
set(LLVM_RELEASE_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "")
set(LLVM_RELEASE_ENABLE_PROJECTS "clang;lld;lldb;clang-tools-extra;bolt;polly;mlir;flang" CACHE STRING "")
# Note we don't need to add install here, since it is one of the pre-defined
Expand Down Expand Up @@ -91,4 +91,6 @@ endif()
# Final Stage Config (stage2)
set_final_stage_var(LLVM_ENABLE_RUNTIMES "${LLVM_RELEASE_ENABLE_RUNTIMES}" STRING)
set_final_stage_var(LLVM_ENABLE_PROJECTS "${LLVM_RELEASE_ENABLE_PROJECTS}" STRING)
set_final_stage_var(CPACK_GENERATOR "TXZ" STRING)
set_final_stage_var(CPACK_ARCHIVE_THREADS "0" STRING)

1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,7 @@ Arm and AArch64 Support
* Arm Cortex-A520AE (cortex-a520ae).
* Arm Cortex-A720AE (cortex-a720ae).
* Arm Cortex-R82AE (cortex-r82ae).
* Arm Cortex-R52+ (cortex-r52plus).
* Arm Neoverse-N3 (neoverse-n3).
* Arm Neoverse-V3 (neoverse-v3).
* Arm Neoverse-V3AE (neoverse-v3ae).
Expand Down
1 change: 1 addition & 0 deletions clang/docs/tools/clang-formatted-files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ clang/tools/libclang/CXCursor.h
clang/tools/scan-build-py/tests/functional/src/include/clean-one.h
clang/unittests/Analysis/CFGBuildResult.h
clang/unittests/Analysis/MacroExpansionContextTest.cpp
clang/unittests/Analysis/FlowSensitive/ASTOpsTest.cpp
clang/unittests/Analysis/FlowSensitive/CNFFormula.cpp
clang/unittests/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
Expand Down
2 changes: 1 addition & 1 deletion clang/examples/PrintFunctionNames/PrintFunctionNames.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class PrintFunctionsConsumer : public ASTConsumer {
*sema.LateParsedTemplateMap.find(FD)->second;
sema.LateTemplateParser(sema.OpaqueParser, LPT);
llvm::errs() << "late-parsed-decl: \"" << FD->getNameAsString() << "\"\n";
}
}
}
};

Expand Down
9 changes: 7 additions & 2 deletions clang/include/clang/AST/ASTUnresolvedSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "clang/AST/ASTVector.h"
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/DeclID.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/Specifiers.h"
#include <cassert>
Expand Down Expand Up @@ -56,6 +57,10 @@ class ASTUnresolvedSet {
Decls.push_back(DeclAccessPair::make(D, AS), C);
}

void addLazyDecl(ASTContext &C, GlobalDeclID ID, AccessSpecifier AS) {
Decls.push_back(DeclAccessPair::makeLazy(ID.get(), AS), C);
}

/// Replaces the given declaration with the new one, once.
///
/// \return true if the set changed
Expand Down Expand Up @@ -109,10 +114,10 @@ class LazyASTUnresolvedSet {

void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); }

void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) {
void addLazyDecl(ASTContext &C, GlobalDeclID ID, AccessSpecifier AS) {
assert(Impl.empty() || Impl.Decls.isLazy());
Impl.Decls.setLazy(true);
Impl.addDecl(C, reinterpret_cast<NamedDecl *>(ID << 2), AS);
Impl.addLazyDecl(C, ID, AS);
}
};

Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/AST/CommentCommands.td
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
// HeaderDoc command for template parameter documentation.
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }

def Throws : BlockCommand<"throws"> { let IsThrowsCommand = 1; }
def Throw : BlockCommand<"throw"> { let IsThrowsCommand = 1; }
def Exception : BlockCommand<"exception"> { let IsThrowsCommand = 1; }
def Throws : BlockCommand<"throws"> { let IsThrowsCommand = 1; let NumArgs = 1; }
def Throw : BlockCommand<"throw"> { let IsThrowsCommand = 1; let NumArgs = 1; }
def Exception : BlockCommand<"exception"> { let IsThrowsCommand = 1; let NumArgs = 1;}

def Deprecated : BlockCommand<"deprecated"> {
let IsEmptyParagraphAllowed = 1;
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/AST/CommentParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ class Parser {
ArrayRef<Comment::Argument>
parseCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs);

/// Parse arguments for \throws command supported args are in form of class
/// or template.
ArrayRef<Comment::Argument>
parseThrowCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs);

BlockCommandComment *parseBlockCommand();
InlineCommandComment *parseInlineCommand();

Expand Down
37 changes: 31 additions & 6 deletions clang/include/clang/AST/DeclAccessPair.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "clang/Basic/Specifiers.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Endian.h"

namespace clang {

Expand All @@ -27,9 +28,17 @@ class NamedDecl;
/// A POD class for pairing a NamedDecl* with an access specifier.
/// Can be put into unions.
class DeclAccessPair {
uintptr_t Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
/// Use the lower 2 bit to store AccessSpecifier. Use the higher
/// 61 bit to store the pointer to a NamedDecl or the DeclID to
/// a NamedDecl. If the 3rd bit is set, storing the DeclID, otherwise
/// storing the pointer.
llvm::support::detail::packed_endian_specific_integral<
uint64_t, llvm::endianness::native, alignof(void *)>
Ptr;

enum { Mask = 0x3 };
enum { ASMask = 0x3, Mask = 0x7 };

bool isDeclID() const { return (Ptr >> 2) & 0x1; }

public:
static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) {
Expand All @@ -38,12 +47,22 @@ class DeclAccessPair {
return p;
}

static DeclAccessPair makeLazy(uint64_t ID, AccessSpecifier AS) {
DeclAccessPair p;
p.Ptr = (ID << 3) | (0x1 << 2) | uint64_t(AS);
return p;
}

uint64_t getDeclID() const {
assert(isDeclID());
return (~Mask & Ptr) >> 3;
}

NamedDecl *getDecl() const {
assert(!isDeclID());
return reinterpret_cast<NamedDecl*>(~Mask & Ptr);
}
AccessSpecifier getAccess() const {
return AccessSpecifier(Mask & Ptr);
}
AccessSpecifier getAccess() const { return AccessSpecifier(ASMask & Ptr); }

void setDecl(NamedDecl *D) {
set(D, getAccess());
Expand All @@ -52,12 +71,18 @@ class DeclAccessPair {
set(getDecl(), AS);
}
void set(NamedDecl *D, AccessSpecifier AS) {
Ptr = uintptr_t(AS) | reinterpret_cast<uintptr_t>(D);
Ptr = uint64_t(AS) | reinterpret_cast<uint64_t>(D);
}

operator NamedDecl*() const { return getDecl(); }
NamedDecl *operator->() const { return getDecl(); }
};

// Make sure DeclAccessPair is pointer-aligned types.
static_assert(alignof(DeclAccessPair) == alignof(void *));
// Make sure DeclAccessPair is still POD.
static_assert(std::is_standard_layout_v<DeclAccessPair> &&
std::is_trivial_v<DeclAccessPair>);
}

#endif
17 changes: 3 additions & 14 deletions clang/include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -708,10 +708,7 @@ class alignas(8) Decl {

/// Set the owning module ID. This may only be called for
/// deserialized Decls.
void setOwningModuleID(unsigned ID) {
assert(isFromASTFile() && "Only works on a deserialized declaration");
*((unsigned*)this - 2) = ID;
}
void setOwningModuleID(unsigned ID);

public:
/// Determine the availability of the given declaration.
Expand Down Expand Up @@ -784,19 +781,11 @@ class alignas(8) Decl {

/// Retrieve the global declaration ID associated with this
/// declaration, which specifies where this Decl was loaded from.
GlobalDeclID getGlobalID() const {
if (isFromASTFile())
return (*((const GlobalDeclID *)this - 1));
return GlobalDeclID();
}
GlobalDeclID getGlobalID() const;

/// Retrieve the global ID of the module that owns this particular
/// declaration.
unsigned getOwningModuleID() const {
if (isFromASTFile())
return *((const unsigned*)this - 2);
return 0;
}
unsigned getOwningModuleID() const;

private:
Module *getOwningModuleSlow() const;
Expand Down
18 changes: 17 additions & 1 deletion clang/include/clang/AST/DeclID.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/iterator.h"

#include <climits>

namespace clang {

/// Predefined declaration IDs.
Expand Down Expand Up @@ -107,12 +109,16 @@ class DeclIDBase {
///
/// DeclID should only be used directly in serialization. All other users
/// should use LocalDeclID or GlobalDeclID.
using DeclID = uint32_t;
using DeclID = uint64_t;

protected:
DeclIDBase() : ID(PREDEF_DECL_NULL_ID) {}
explicit DeclIDBase(DeclID ID) : ID(ID) {}

explicit DeclIDBase(unsigned LocalID, unsigned ModuleFileIndex) {
ID = (DeclID)LocalID | ((DeclID)ModuleFileIndex << 32);
}

public:
DeclID get() const { return ID; }

Expand All @@ -124,6 +130,10 @@ class DeclIDBase {

bool isInvalid() const { return ID == PREDEF_DECL_NULL_ID; }

unsigned getModuleFileIndex() const { return ID >> 32; }

unsigned getLocalDeclIndex() const;

friend bool operator==(const DeclIDBase &LHS, const DeclIDBase &RHS) {
return LHS.ID == RHS.ID;
}
Expand Down Expand Up @@ -156,6 +166,9 @@ class LocalDeclID : public DeclIDBase {
LocalDeclID(PredefinedDeclIDs ID) : Base(ID) {}
explicit LocalDeclID(DeclID ID) : Base(ID) {}

explicit LocalDeclID(unsigned LocalID, unsigned ModuleFileIndex)
: Base(LocalID, ModuleFileIndex) {}

LocalDeclID &operator++() {
++ID;
return *this;
Expand All @@ -175,6 +188,9 @@ class GlobalDeclID : public DeclIDBase {
GlobalDeclID() : Base() {}
explicit GlobalDeclID(DeclID ID) : Base(ID) {}

explicit GlobalDeclID(unsigned LocalID, unsigned ModuleFileIndex)
: Base(LocalID, ModuleFileIndex) {}

// For DeclIDIterator<GlobalDeclID> to be able to convert a GlobalDeclID
// to a LocalDeclID.
explicit operator LocalDeclID() const { return LocalDeclID(this->ID); }
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/TemplateBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ class TemplateArgument {
bool IncludeType) const;

/// Debugging aid that dumps the template argument.
void dump(raw_ostream &Out) const;
void dump(raw_ostream &Out, const ASTContext &Context) const;

/// Debugging aid that dumps the template argument to standard error.
void dump() const;
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/TemplateName.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ class TemplateName {
Qualified Qual = Qualified::AsWritten) const;

/// Debugging aid that dumps the template name.
void dump(raw_ostream &OS) const;
void dump(raw_ostream &OS, const ASTContext &Context) const;

/// Debugging aid that dumps the template name to standard
/// error.
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/UnresolvedSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class UnresolvedSetIterator : public llvm::iterator_adaptor_base<
// temporaries with defaulted ctors are not zero initialized.
UnresolvedSetIterator() : iterator_adaptor_base(nullptr) {}

uint64_t getDeclID() const { return I->getDeclID(); }
NamedDecl *getDecl() const { return I->getDecl(); }
void setDecl(NamedDecl *ND) const { return I->setDecl(ND); }
AccessSpecifier getAccess() const { return I->getAccess(); }
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,9 @@ class CapabilityExpr {

bool shouldIgnore() const { return sexpr() == nullptr; }

bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); }
bool isInvalid() const { return isa_and_nonnull<til::Undefined>(sexpr()); }

bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); }
bool isUniversal() const { return isa_and_nonnull<til::Wildcard>(sexpr()); }
};

// Translate clang::Expr to til::SExpr.
Expand Down
27 changes: 5 additions & 22 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -4470,37 +4470,20 @@ def HLSLShader : InheritableAttr {
let Subjects = SubjectList<[HLSLEntry]>;
let LangOpts = [HLSL];
let Args = [
EnumArgument<"Type", "ShaderType", /*is_string=*/true,
EnumArgument<"Type", "llvm::Triple::EnvironmentType", /*is_string=*/true,
["pixel", "vertex", "geometry", "hull", "domain", "compute",
"raygeneration", "intersection", "anyhit", "closesthit",
"miss", "callable", "mesh", "amplification"],
["Pixel", "Vertex", "Geometry", "Hull", "Domain", "Compute",
"RayGeneration", "Intersection", "AnyHit", "ClosestHit",
"Miss", "Callable", "Mesh", "Amplification"]>
"Miss", "Callable", "Mesh", "Amplification"],
/*opt=*/0, /*fake=*/0, /*isExternalType=*/1>
];
let Documentation = [HLSLSV_ShaderTypeAttrDocs];
let AdditionalMembers =
[{
static const unsigned ShaderTypeMaxValue = (unsigned)HLSLShaderAttr::Amplification;

static llvm::Triple::EnvironmentType getTypeAsEnvironment(HLSLShaderAttr::ShaderType ShaderType) {
switch (ShaderType) {
case HLSLShaderAttr::Pixel: return llvm::Triple::Pixel;
case HLSLShaderAttr::Vertex: return llvm::Triple::Vertex;
case HLSLShaderAttr::Geometry: return llvm::Triple::Geometry;
case HLSLShaderAttr::Hull: return llvm::Triple::Hull;
case HLSLShaderAttr::Domain: return llvm::Triple::Domain;
case HLSLShaderAttr::Compute: return llvm::Triple::Compute;
case HLSLShaderAttr::RayGeneration: return llvm::Triple::RayGeneration;
case HLSLShaderAttr::Intersection: return llvm::Triple::Intersection;
case HLSLShaderAttr::AnyHit: return llvm::Triple::AnyHit;
case HLSLShaderAttr::ClosestHit: return llvm::Triple::ClosestHit;
case HLSLShaderAttr::Miss: return llvm::Triple::Miss;
case HLSLShaderAttr::Callable: return llvm::Triple::Callable;
case HLSLShaderAttr::Mesh: return llvm::Triple::Mesh;
case HLSLShaderAttr::Amplification: return llvm::Triple::Amplification;
}
llvm_unreachable("unknown enumeration value");
static bool isValidShaderType(llvm::Triple::EnvironmentType ShaderType) {
return ShaderType >= llvm::Triple::Pixel && ShaderType <= llvm::Triple::Amplification;
}
}];
}
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -482,11 +482,11 @@ def SqrtF16F128 : Builtin, F16F128MathTemplate {
let Prototype = "T(T)";
}

def TanF128 : Builtin {
let Spellings = ["__builtin_tanf128"];
def TanF16F128 : Builtin, F16F128MathTemplate {
let Spellings = ["__builtin_tan"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow,
ConstIgnoringErrnoAndExceptions];
let Prototype = "__float128(__float128)";
let Prototype = "T(T)";
}

def TanhF128 : Builtin {
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ CODEGENOPT(SeparateNamedSections, 1, 0) ///< Set for -fseparate-named-sections.
CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX.
CODEGENOPT(XCOFFReadOnlyPointers, 1, 0) ///< Set for -mxcoff-roptr.
CODEGENOPT(AllTocData, 1, 0) ///< AIX -mtocdata
ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none
ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,reserved,none

CODEGENOPT(ClearASTBeforeBackend , 1, 0) ///< Free the AST before running backend code generation. Only works with -disable-free.
CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory.
Expand Down
9 changes: 6 additions & 3 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,18 @@ class CodeGenOptions : public CodeGenOptionsBase {
std::string BinutilsVersion;

enum class FramePointerKind {
None, // Omit all frame pointers.
NonLeaf, // Keep non-leaf frame pointers.
All, // Keep all frame pointers.
None, // Omit all frame pointers.
Reserved, // Maintain valid frame pointer chain.
NonLeaf, // Keep non-leaf frame pointers.
All, // Keep all frame pointers.
};

static StringRef getFramePointerKindName(FramePointerKind Kind) {
switch (Kind) {
case FramePointerKind::None:
return "none";
case FramePointerKind::Reserved:
return "reserved";
case FramePointerKind::NonLeaf:
return "non-leaf";
case FramePointerKind::All:
Expand Down
13 changes: 10 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,8 @@ def note_using_decl_class_member_workaround : Note<
"a const variable|a constexpr variable}0 instead">;
def err_using_decl_can_not_refer_to_namespace : Error<
"using declaration cannot refer to a namespace">;
def note_namespace_using_decl : Note<
"did you mean 'using namespace'?">;
def warn_cxx17_compat_using_decl_scoped_enumerator: Warning<
"using declaration naming a scoped enumerator is incompatible with "
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
Expand Down Expand Up @@ -6088,9 +6090,9 @@ def err_redefinition_different_concept : Error<
"redefinition of concept %0 with different template parameters or requirements">;
def err_tag_reference_non_tag : Error<
"%select{non-struct type|non-class type|non-union type|non-enum "
"type|typedef|type alias|template|type alias template|template "
"template argument}1 %0 cannot be referenced with a "
"%select{struct|interface|union|class|enum}2 specifier">;
"type|typedef|type alias|template|alias template|template "
"template argument}1 %0 cannot be referenced with the '"
"%select{struct|interface|union|class|enum}2' specifier">;
def err_tag_reference_conflict : Error<
"implicit declaration introduced by elaborated type conflicts with a "
"%select{non-struct type|non-class type|non-union type|non-enum "
Expand Down Expand Up @@ -9013,6 +9015,11 @@ def err_cuda_ovl_target : Error<
"cannot overload %select{__device__|__global__|__host__|__host__ __device__}2 function %3">;
def note_cuda_ovl_candidate_target_mismatch : Note<
"candidate template ignored: target attributes do not match">;
def warn_offload_incompatible_redeclare : Warning<
"target-attribute based function overloads are not supported by NVCC and will be treated as a function redeclaration:"
"new declaration is %select{__device__|__global__|__host__|__host__ __device__}0 function, "
"old declaration is %select{__device__|__global__|__host__|__host__ __device__}1 function">,
InGroup<DiagGroup<"nvcc-compat">>, DefaultIgnore;

def err_cuda_device_builtin_surftex_cls_template : Error<
"illegal device builtin %select{surface|texture}0 reference "
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ FEATURE(nullability, true)
FEATURE(nullability_on_arrays, true)
FEATURE(nullability_on_classes, true)
FEATURE(nullability_nullable_result, true)
FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::NumericalStability))
FEATURE(memory_sanitizer,
LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |
SanitizerKind::KernelMemory))
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/Sanitizers.def
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ SANITIZER("fuzzer-no-link", FuzzerNoLink)
// ThreadSanitizer
SANITIZER("thread", Thread)

// Numerical stability sanitizer.
SANITIZER("numerical", NumericalStability)

// LeakSanitizer
SANITIZER("leak", Leak)

Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -7724,8 +7724,8 @@ def pic_is_pie : Flag<["-"], "pic-is-pie">,
MarshallingInfoFlag<LangOpts<"PIE">>;

def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">,
HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,none">,
NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "None"]>,
HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,reserved,none">,
NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "Reserved", "None"]>,
MarshallingInfoEnum<CodeGenOpts<"FramePointer">, "None">;


Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Driver/SanitizerArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class SanitizerArgs {
bool needsCfiDiagRt() const;
bool needsStatsRt() const { return Stats; }
bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); }
bool needsNsanRt() const {
return Sanitizers.has(SanitizerKind::NumericalStability);
}

bool hasMemTag() const {
return hasMemtagHeap() || hasMemtagStack() || hasMemtagGlobals();
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Driver/ToolChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ class ToolChain {

/// Executes the given \p Executable and returns the stdout.
llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
executeToolChainProgram(StringRef Executable) const;
executeToolChainProgram(StringRef Executable,
unsigned SecondsToWait = 0) const;

void setTripleEnvironment(llvm::Triple::EnvironmentType Env);

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,7 @@ class Preprocessor {

MacroState &S = CurSubmoduleState->Macros[II];
auto *MD = S.getLatest();
while (MD && isa<VisibilityMacroDirective>(MD))
while (isa_and_nonnull<VisibilityMacroDirective>(MD))
MD = MD->getPrevious();
return MacroDefinition(dyn_cast_or_null<DefMacroDirective>(MD),
S.getActiveModuleMacros(*this, II),
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/Initialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class alignas(8) InitializedEntity {
struct C Capture;
};

InitializedEntity() {};
InitializedEntity() {}

/// Create the initialization entity for a variable.
InitializedEntity(VarDecl *Var, EntityKind EK = EK_Variable)
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class SemaHLSL : public SemaBase {
const AttributeCommonInfo &AL, int X,
int Y, int Z);
HLSLShaderAttr *mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLShaderAttr::ShaderType ShaderType);
llvm::Triple::EnvironmentType ShaderType);
HLSLParamModifierAttr *
mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLParamModifierAttr::Spelling Spelling);
Expand All @@ -48,8 +48,8 @@ class SemaHLSL : public SemaBase {
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
const HLSLAnnotationAttr *AnnotationAttr);
void DiagnoseAttrStageMismatch(
const Attr *A, HLSLShaderAttr::ShaderType Stage,
std::initializer_list<HLSLShaderAttr::ShaderType> AllowedStages);
const Attr *A, llvm::Triple::EnvironmentType Stage,
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages);
void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU);

void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/SemaObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ class SemaObjC : public SemaBase {
void AddAnyMethodToGlobalPool(Decl *D);

void ActOnStartOfObjCMethodDef(Scope *S, Decl *D);
bool isObjCMethodDecl(Decl *D) { return D && isa<ObjCMethodDecl>(D); }
bool isObjCMethodDecl(Decl *D) { return isa_and_nonnull<ObjCMethodDecl>(D); }

/// CheckImplementationIvars - This routine checks if the instance variables
/// listed in the implelementation match those listed in the interface.
Expand Down
29 changes: 23 additions & 6 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ class DeclOffset {
}
};

// The unaligned decl ID used in the Blobs of bistreams.
using unaligned_decl_id_t =
llvm::support::detail::packed_endian_specific_integral<
serialization::DeclID, llvm::endianness::native,
llvm::support::unaligned>;

/// The number of predefined preprocessed entity IDs.
const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1;

Expand Down Expand Up @@ -1980,33 +1986,44 @@ enum CleanupObjectKind { COK_Block, COK_CompoundLiteral };

/// Describes the categories of an Objective-C class.
struct ObjCCategoriesInfo {
// The ID of the definition
LocalDeclID DefinitionID;
// The ID of the definition. Use unaligned_decl_id_t to keep
// ObjCCategoriesInfo 32-bit aligned.
unaligned_decl_id_t DefinitionID;

// Offset into the array of category lists.
unsigned Offset;

ObjCCategoriesInfo() = default;
ObjCCategoriesInfo(LocalDeclID ID, unsigned Offset)
: DefinitionID(ID.get()), Offset(Offset) {}

LocalDeclID getDefinitionID() const { return LocalDeclID(DefinitionID); }

friend bool operator<(const ObjCCategoriesInfo &X,
const ObjCCategoriesInfo &Y) {
return X.DefinitionID < Y.DefinitionID;
return X.getDefinitionID() < Y.getDefinitionID();
}

friend bool operator>(const ObjCCategoriesInfo &X,
const ObjCCategoriesInfo &Y) {
return X.DefinitionID > Y.DefinitionID;
return X.getDefinitionID() > Y.getDefinitionID();
}

friend bool operator<=(const ObjCCategoriesInfo &X,
const ObjCCategoriesInfo &Y) {
return X.DefinitionID <= Y.DefinitionID;
return X.getDefinitionID() <= Y.getDefinitionID();
}

friend bool operator>=(const ObjCCategoriesInfo &X,
const ObjCCategoriesInfo &Y) {
return X.DefinitionID >= Y.DefinitionID;
return X.getDefinitionID() >= Y.getDefinitionID();
}
};

static_assert(alignof(ObjCCategoriesInfo) <= 4);
static_assert(std::is_standard_layout_v<ObjCCategoriesInfo> &&
std::is_trivial_v<ObjCCategoriesInfo>);

/// A key used when looking up entities by \ref DeclarationName.
///
/// Different \ref DeclarationNames are mapped to different keys, but the
Expand Down
36 changes: 16 additions & 20 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,12 +504,6 @@ class ASTReader
/// = I + 1 has already been loaded.
llvm::PagedVector<Decl *> DeclsLoaded;

using GlobalDeclMapType = ContinuousRangeMap<GlobalDeclID, ModuleFile *, 4>;

/// Mapping from global declaration IDs to the module in which the
/// declaration resides.
GlobalDeclMapType GlobalDeclMap;

using FileOffset = std::pair<ModuleFile *, uint64_t>;
using FileOffsetsTy = SmallVector<FileOffset, 2>;
using DeclUpdateOffsetsMap = llvm::DenseMap<GlobalDeclID, FileOffsetsTy>;
Expand Down Expand Up @@ -592,10 +586,11 @@ class ASTReader

struct FileDeclsInfo {
ModuleFile *Mod = nullptr;
ArrayRef<LocalDeclID> Decls;
ArrayRef<serialization::unaligned_decl_id_t> Decls;

FileDeclsInfo() = default;
FileDeclsInfo(ModuleFile *Mod, ArrayRef<LocalDeclID> Decls)
FileDeclsInfo(ModuleFile *Mod,
ArrayRef<serialization::unaligned_decl_id_t> Decls)
: Mod(Mod), Decls(Decls) {}
};

Expand All @@ -604,11 +599,7 @@ class ASTReader

/// An array of lexical contents of a declaration context, as a sequence of
/// Decl::Kind, DeclID pairs.
using unaligned_decl_id_t =
llvm::support::detail::packed_endian_specific_integral<
serialization::DeclID, llvm::endianness::native,
llvm::support::unaligned>;
using LexicalContents = ArrayRef<unaligned_decl_id_t>;
using LexicalContents = ArrayRef<serialization::unaligned_decl_id_t>;

/// Map from a DeclContext to its lexical contents.
llvm::DenseMap<const DeclContext*, std::pair<ModuleFile*, LexicalContents>>
Expand Down Expand Up @@ -1489,22 +1480,23 @@ class ASTReader
unsigned ClientLoadCapabilities);

public:
class ModuleDeclIterator : public llvm::iterator_adaptor_base<
ModuleDeclIterator, const LocalDeclID *,
std::random_access_iterator_tag, const Decl *,
ptrdiff_t, const Decl *, const Decl *> {
class ModuleDeclIterator
: public llvm::iterator_adaptor_base<
ModuleDeclIterator, const serialization::unaligned_decl_id_t *,
std::random_access_iterator_tag, const Decl *, ptrdiff_t,
const Decl *, const Decl *> {
ASTReader *Reader = nullptr;
ModuleFile *Mod = nullptr;

public:
ModuleDeclIterator() : iterator_adaptor_base(nullptr) {}

ModuleDeclIterator(ASTReader *Reader, ModuleFile *Mod,
const LocalDeclID *Pos)
const serialization::unaligned_decl_id_t *Pos)
: iterator_adaptor_base(Pos), Reader(Reader), Mod(Mod) {}

value_type operator*() const {
return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, *I));
return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, (LocalDeclID)*I));
}

value_type operator->() const { return **this; }
Expand Down Expand Up @@ -1544,6 +1536,9 @@ class ASTReader
StringRef Arg2 = StringRef(), StringRef Arg3 = StringRef()) const;
void Error(llvm::Error &&Err) const;

/// Translate a \param GlobalDeclID to the index of DeclsLoaded array.
unsigned translateGlobalDeclIDToIndex(GlobalDeclID ID) const;

public:
/// Load the AST file and validate its contents against the given
/// Preprocessor.
Expand Down Expand Up @@ -1915,7 +1910,8 @@ class ASTReader

/// Retrieve the module file that owns the given declaration, or NULL
/// if the declaration is not from a module file.
ModuleFile *getOwningModuleFile(const Decl *D);
ModuleFile *getOwningModuleFile(const Decl *D) const;
ModuleFile *getOwningModuleFile(GlobalDeclID ID) const;

/// Returns the source location for the decl \p ID.
SourceLocation getSourceLocationForDeclID(GlobalDeclID ID);
Expand Down
Loading