10 changes: 7 additions & 3 deletions bolt/test/X86/sctc-bug4.test
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
# Check that fallthrough blocks are handled properly.
# Check that fallthrough blocks are handled properly and Offset annotation is
# set for conditional tail calls.

RUN: %clang %cflags %S/Inputs/sctc_bug4.s -o %t
RUN: llvm-bolt %t -o %t.null \
RUN: llvm-bolt %t -o %t.null --enable-bat \
RUN: -funcs=test_func -print-sctc -sequential-disassembly 2>&1 | FileCheck %s

CHECK: .Ltmp2 (3 instructions, align : 1)
CHECK-NEXT: CFI State : 0
CHECK-NEXT: Input offset: 0x24
CHECK-NEXT: Predecessors: .LFT1
CHECK-NEXT: 00000024: cmpq $0x20, %rsi
CHECK-NEXT: 00000028: ja dummy # TAILCALL {{.*}}# CTCTakenCount: 0
CHECK-NEXT: 00000028: ja dummy # TAILCALL # Offset: 53 # CTCTakenCount: 0
CHECK-NEXT: 0000002a: jmp .Ltmp4
CHECK-NEXT: Successors: .Ltmp4
CHECK-NEXT: CFI State: 0

CHECK: .Ltmp1 (2 instructions, align : 1)
CHECK-NEXT: CFI State : 0
CHECK-NEXT: Input offset: 0x2c
CHECK-NEXT: Predecessors: .LFT0
CHECK-NEXT: 0000002c: xorq %r11, %rax
CHECK-NEXT: 0000002f: retq
CHECK-NEXT: CFI State: 0

CHECK: .Ltmp4 (4 instructions, align : 1)
CHECK-NEXT: CFI State : 0
CHECK-NEXT: Input offset: 0x3a
CHECK-NEXT: Predecessors: .Ltmp2
4 changes: 2 additions & 2 deletions bolt/test/runtime/bolt-reserved.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* not enough for allocating new sections.
*/

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

// CHECK-TINY: BOLT-ERROR: reserved space (1 byte) is smaller than required
Expand Down
22 changes: 22 additions & 0 deletions clang-tools-extra/clang-query/Query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "Query.h"
#include "QueryParser.h"
#include "QuerySession.h"
#include "clang/AST/ASTDumper.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
Expand Down Expand Up @@ -281,5 +282,26 @@ const QueryKind SetQueryKind<bool>::value;
const QueryKind SetQueryKind<OutputKind>::value;
#endif

bool FileQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
auto Buffer = llvm::MemoryBuffer::getFile(StringRef{File}.trim());
if (!Buffer) {
if (Prefix.has_value())
llvm::errs() << *Prefix << ": ";
llvm::errs() << "cannot open " << File << ": "
<< Buffer.getError().message() << "\n";
return false;
}

StringRef FileContentRef(Buffer.get()->getBuffer());

while (!FileContentRef.empty()) {
QueryRef Q = QueryParser::parse(FileContentRef, QS);
if (!Q->run(llvm::outs(), QS))
return false;
FileContentRef = Q->RemainingContent;
}
return true;
}

} // namespace query
} // namespace clang
18 changes: 17 additions & 1 deletion clang-tools-extra/clang-query/Query.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ enum QueryKind {
QK_SetTraversalKind,
QK_EnableOutputKind,
QK_DisableOutputKind,
QK_Quit
QK_Quit,
QK_File
};

class QuerySession;
Expand Down Expand Up @@ -188,6 +189,21 @@ struct DisableOutputQuery : SetNonExclusiveOutputQuery {
}
};

struct FileQuery : Query {
FileQuery(StringRef File, StringRef Prefix = StringRef())
: Query(QK_File), File(File),
Prefix(!Prefix.empty() ? std::optional<std::string>(Prefix)
: std::nullopt) {}

bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;

static bool classof(const Query *Q) { return Q->Kind == QK_File; }

private:
std::string File;
std::optional<std::string> Prefix;
};

} // namespace query
} // namespace clang

Expand Down
10 changes: 8 additions & 2 deletions clang-tools-extra/clang-query/QueryParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ enum ParsedQueryKind {
PQK_Unlet,
PQK_Quit,
PQK_Enable,
PQK_Disable
PQK_Disable,
PQK_File
};

enum ParsedQueryVariable {
Expand Down Expand Up @@ -222,12 +223,14 @@ QueryRef QueryParser::doParse() {
.Case("let", PQK_Let)
.Case("m", PQK_Match, /*IsCompletion=*/false)
.Case("match", PQK_Match)
.Case("q", PQK_Quit, /*IsCompletion=*/false)
.Case("q", PQK_Quit, /*IsCompletion=*/false)
.Case("quit", PQK_Quit)
.Case("set", PQK_Set)
.Case("enable", PQK_Enable)
.Case("disable", PQK_Disable)
.Case("unlet", PQK_Unlet)
.Case("f", PQK_File, /*IsCompletion=*/false)
.Case("file", PQK_File)
.Default(PQK_Invalid);

switch (QKind) {
Expand Down Expand Up @@ -351,6 +354,9 @@ QueryRef QueryParser::doParse() {
return endQuery(new LetQuery(Name, VariantValue()));
}

case PQK_File:
return new FileQuery(Line);

case PQK_Invalid:
return new InvalidQuery("unknown command: " + CommandStr);
}
Expand Down
18 changes: 2 additions & 16 deletions clang-tools-extra/clang-query/tool/ClangQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,8 @@ static cl::opt<std::string> PreloadFile(

bool runCommandsInFile(const char *ExeName, std::string const &FileName,
QuerySession &QS) {
auto Buffer = llvm::MemoryBuffer::getFile(FileName);
if (!Buffer) {
llvm::errs() << ExeName << ": cannot open " << FileName << ": "
<< Buffer.getError().message() << "\n";
return true;
}

StringRef FileContentRef(Buffer.get()->getBuffer());

while (!FileContentRef.empty()) {
QueryRef Q = QueryParser::parse(FileContentRef, QS);
if (!Q->run(llvm::outs(), QS))
return true;
FileContentRef = Q->RemainingContent;
}
return false;
FileQuery Query(FileName, ExeName);
return !Query.run(llvm::errs(), QS);
}

int main(int argc, const char **argv) {
Expand Down
10 changes: 5 additions & 5 deletions clang-tools-extra/clang-tidy/ClangTidy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,11 +373,11 @@ static CheckersList getAnalyzerCheckersAndPackages(ClangTidyContext &Context,

const auto &RegisteredCheckers =
AnalyzerOptions::getRegisteredCheckers(IncludeExperimental);
bool AnalyzerChecksEnabled = false;
for (StringRef CheckName : RegisteredCheckers) {
std::string ClangTidyCheckName((AnalyzerCheckNamePrefix + CheckName).str());
AnalyzerChecksEnabled |= Context.isCheckEnabled(ClangTidyCheckName);
}
const bool AnalyzerChecksEnabled =
llvm::any_of(RegisteredCheckers, [&](StringRef CheckName) -> bool {
return Context.isCheckEnabled(
(AnalyzerCheckNamePrefix + CheckName).str());
});

if (!AnalyzerChecksEnabled)
return List;
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/ClangTidyCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ std::optional<int64_t> ClangTidyCheck::OptionsView::getEnumInt(
if (IgnoreCase) {
if (Value.equals_insensitive(NameAndEnum.second))
return NameAndEnum.first;
} else if (Value.equals(NameAndEnum.second)) {
} else if (Value == NameAndEnum.second) {
return NameAndEnum.first;
} else if (Value.equals_insensitive(NameAndEnum.second)) {
Closest = NameAndEnum.second;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ AST_MATCHER(QualType, isEnableIf) {
const NamedDecl *TypeDecl =
Spec->getTemplateName().getAsTemplateDecl()->getTemplatedDecl();
return TypeDecl->isInStdNamespace() &&
(TypeDecl->getName().equals("enable_if") ||
TypeDecl->getName().equals("enable_if_t"));
(TypeDecl->getName() == "enable_if" ||
TypeDecl->getName() == "enable_if_t");
};
const Type *BaseType = Node.getTypePtr();
// Case: pointer or reference to enable_if.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) {
ofClass(matchers::matchesAnyListedName(OptionalTypes)))),
hasType(ConstructTypeMatcher),
hasArgument(0U, ignoringImpCasts(anyOf(OptionalDereferenceMatcher,
StdMoveCallMatcher))))
StdMoveCallMatcher))),
unless(anyOf(hasAncestor(typeLoc()),
hasAncestor(expr(matchers::hasUnevaluatedContext())))))
.bind("expr"),
this);
}
Expand Down
5 changes: 3 additions & 2 deletions clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "SignedBitwiseCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"

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

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ add_clang_library(clangTidyModernizeModule
UseNullptrCheck.cpp
UseOverrideCheck.cpp
UseStartsEndsWithCheck.cpp
UseStdFormatCheck.cpp
UseStdNumbersCheck.cpp
UseStdPrintCheck.cpp
UseTrailingReturnTypeCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ getContainerFromBeginEndCall(const Expr *Init, bool IsBegin, bool *IsArrow,
return {};
if (IsReverse && !Call->Name.consume_back("r"))
return {};
if (!Call->Name.empty() && !Call->Name.equals("c"))
if (!Call->Name.empty() && Call->Name != "c")
return {};
return std::make_pair(Call->Container, Call->CallKind);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "UseNullptrCheck.h"
#include "UseOverrideCheck.h"
#include "UseStartsEndsWithCheck.h"
#include "UseStdFormatCheck.h"
#include "UseStdNumbersCheck.h"
#include "UseStdPrintCheck.h"
#include "UseTrailingReturnTypeCheck.h"
Expand Down Expand Up @@ -76,6 +77,7 @@ class ModernizeModule : public ClangTidyModule {
"modernize-use-designated-initializers");
CheckFactories.registerCheck<UseStartsEndsWithCheck>(
"modernize-use-starts-ends-with");
CheckFactories.registerCheck<UseStdFormatCheck>("modernize-use-std-format");
CheckFactories.registerCheck<UseStdNumbersCheck>(
"modernize-use-std-numbers");
CheckFactories.registerCheck<UseStdPrintCheck>("modernize-use-std-print");
Expand Down
107 changes: 107 additions & 0 deletions clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//===--- UseStdFormatCheck.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 "UseStdFormatCheck.h"
#include "../utils/FormatStringConverter.h"
#include "../utils/Matchers.h"
#include "../utils/OptionsUtils.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/FixIt.h"

using namespace clang::ast_matchers;

namespace clang::tidy::modernize {

namespace {
AST_MATCHER(StringLiteral, isOrdinary) { return Node.isOrdinary(); }
} // namespace

UseStdFormatCheck::UseStdFormatCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
StrictMode(Options.getLocalOrGlobal("StrictMode", false)),
StrFormatLikeFunctions(utils::options::parseStringList(
Options.get("StrFormatLikeFunctions", ""))),
ReplacementFormatFunction(
Options.get("ReplacementFormatFunction", "std::format")),
IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
utils::IncludeSorter::IS_LLVM),
areDiagsSelfContained()),
MaybeHeaderToInclude(Options.get("FormatHeader")) {
if (StrFormatLikeFunctions.empty())
StrFormatLikeFunctions.push_back("absl::StrFormat");

if (!MaybeHeaderToInclude && ReplacementFormatFunction == "std::format")
MaybeHeaderToInclude = "<format>";
}

void UseStdFormatCheck::registerPPCallbacks(const SourceManager &SM,
Preprocessor *PP,
Preprocessor *ModuleExpanderPP) {
IncludeInserter.registerPreprocessor(PP);
}

void UseStdFormatCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
callExpr(argumentCountAtLeast(1),
hasArgument(0, stringLiteral(isOrdinary())),
callee(functionDecl(unless(cxxMethodDecl()),
matchers::matchesAnyListedName(
StrFormatLikeFunctions))
.bind("func_decl")))
.bind("strformat"),
this);
}

void UseStdFormatCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
using utils::options::serializeStringList;
Options.store(Opts, "StrictMode", StrictMode);
Options.store(Opts, "StrFormatLikeFunctions",
serializeStringList(StrFormatLikeFunctions));
Options.store(Opts, "ReplacementFormatFunction", ReplacementFormatFunction);
Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
if (MaybeHeaderToInclude)
Options.store(Opts, "FormatHeader", *MaybeHeaderToInclude);
}

void UseStdFormatCheck::check(const MatchFinder::MatchResult &Result) {
const unsigned FormatArgOffset = 0;
const auto *OldFunction = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
const auto *StrFormat = Result.Nodes.getNodeAs<CallExpr>("strformat");

utils::FormatStringConverter::Configuration ConverterConfig;
ConverterConfig.StrictMode = StrictMode;
utils::FormatStringConverter Converter(Result.Context, StrFormat,
FormatArgOffset, ConverterConfig,
getLangOpts());
const Expr *StrFormatCall = StrFormat->getCallee();
if (!Converter.canApply()) {
diag(StrFormat->getBeginLoc(),
"unable to use '%0' instead of %1 because %2")
<< StrFormatCall->getSourceRange() << ReplacementFormatFunction
<< OldFunction->getIdentifier()
<< Converter.conversionNotPossibleReason();
return;
}

DiagnosticBuilder Diag =
diag(StrFormatCall->getBeginLoc(), "use '%0' instead of %1")
<< ReplacementFormatFunction << OldFunction->getIdentifier();
Diag << FixItHint::CreateReplacement(
CharSourceRange::getTokenRange(StrFormatCall->getSourceRange()),
ReplacementFormatFunction);
Converter.applyFixes(Diag, *Result.SourceManager);

if (MaybeHeaderToInclude)
Diag << IncludeInserter.createIncludeInsertion(
Result.Context->getSourceManager().getFileID(
StrFormatCall->getBeginLoc()),
*MaybeHeaderToInclude);
}

} // namespace clang::tidy::modernize
51 changes: 51 additions & 0 deletions clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//===--- UseStdFormatCheck.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_MODERNIZE_USESTDFORMATCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDFORMATCHECK_H

#include "../ClangTidyCheck.h"
#include "../utils/IncludeInserter.h"

namespace clang::tidy::modernize {

/// Converts calls to absl::StrFormat, or other functions via configuration
/// options, to C++20's std::format, or another function via a configuration
/// option, modifying the format string appropriately and removing
/// now-unnecessary calls to std::string::c_str() and std::string::data().
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-format.html
class UseStdFormatCheck : public ClangTidyCheck {
public:
UseStdFormatCheck(StringRef Name, ClangTidyContext *Context);
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
if (ReplacementFormatFunction == "std::format")
return LangOpts.CPlusPlus20;
return LangOpts.CPlusPlus;
}
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
Preprocessor *ModuleExpanderPP) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
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:
bool StrictMode;
std::vector<StringRef> StrFormatLikeFunctions;
StringRef ReplacementFormatFunction;
utils::IncludeInserter IncludeInserter;
std::optional<StringRef> MaybeHeaderToInclude;
};

} // namespace clang::tidy::modernize

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDFORMATCHECK_H
5 changes: 4 additions & 1 deletion clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,11 @@ void UseStdPrintCheck::check(const MatchFinder::MatchResult &Result) {
FormatArgOffset = 1;
}

utils::FormatStringConverter::Configuration ConverterConfig;
ConverterConfig.StrictMode = StrictMode;
ConverterConfig.AllowTrailingNewlineRemoval = true;
utils::FormatStringConverter Converter(
Result.Context, Printf, FormatArgOffset, StrictMode, getLangOpts());
Result.Context, Printf, FormatArgOffset, ConverterConfig, getLangOpts());
const Expr *PrintfCall = Printf->getCallee();
const StringRef ReplacementFunction = Converter.usePrintNewlineFunction()
? ReplacementPrintlnFunction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ static bool containsDeclInScope(const Stmt *Node) {
}

static void removeElseAndBrackets(DiagnosticBuilder &Diag, ASTContext &Context,
const Stmt *Else, SourceLocation ElseLoc) {
const Stmt *Else, SourceLocation ElseLoc) {
auto Remap = [&](SourceLocation Loc) {
return Context.getSourceManager().getExpansionLoc(Loc);
};
Expand Down Expand Up @@ -172,7 +172,7 @@ void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) {
breakStmt().bind(InterruptingStr), cxxThrowExpr().bind(InterruptingStr)));
Finder->addMatcher(
compoundStmt(
forEach(ifStmt(unless(isConstexpr()),
forEach(ifStmt(unless(isConstexpr()), unless(isConsteval()),
hasThen(stmt(
anyOf(InterruptsControlFlow,
compoundStmt(has(InterruptsControlFlow))))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1358,7 +1358,7 @@ IdentifierNamingCheck::getFailureInfo(
std::replace(KindName.begin(), KindName.end(), '_', ' ');

std::string Fixup = fixupWithStyle(Type, Name, Style, HNOption, ND);
if (StringRef(Fixup).equals(Name)) {
if (StringRef(Fixup) == Name) {
if (!IgnoreFailedSplit) {
LLVM_DEBUG(Location.print(llvm::dbgs(), SM);
llvm::dbgs()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "SimplifyBooleanExprCheck.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/SaveAndRestore.h"
Expand Down Expand Up @@ -280,9 +281,8 @@ class SimplifyBooleanExprCheck::Visitor : public RecursiveASTVisitor<Visitor> {
if (!S) {
return true;
}
if (Check->IgnoreMacros && S->getBeginLoc().isMacroID()) {
if (Check->canBeBypassed(S))
return false;
}
if (!shouldIgnore(S))
StmtStack.push_back(S);
return true;
Expand Down Expand Up @@ -513,17 +513,23 @@ class SimplifyBooleanExprCheck::Visitor : public RecursiveASTVisitor<Visitor> {
return true;
}

static bool isUnaryLNot(const Expr *E) {
return isa<UnaryOperator>(E) &&
bool isExpectedUnaryLNot(const Expr *E) {
return !Check->canBeBypassed(E) && isa<UnaryOperator>(E) &&
cast<UnaryOperator>(E)->getOpcode() == UO_LNot;
}

bool isExpectedBinaryOp(const Expr *E) {
const auto *BinaryOp = dyn_cast<BinaryOperator>(E);
return !Check->canBeBypassed(E) && BinaryOp && BinaryOp->isLogicalOp() &&
BinaryOp->getType()->isBooleanType();
}

template <typename Functor>
static bool checkEitherSide(const BinaryOperator *BO, Functor Func) {
return Func(BO->getLHS()) || Func(BO->getRHS());
}

static bool nestedDemorgan(const Expr *E, unsigned NestingLevel) {
bool nestedDemorgan(const Expr *E, unsigned NestingLevel) {
const auto *BO = dyn_cast<BinaryOperator>(E->IgnoreUnlessSpelledInSource());
if (!BO)
return false;
Expand All @@ -539,15 +545,13 @@ class SimplifyBooleanExprCheck::Visitor : public RecursiveASTVisitor<Visitor> {
return true;
case BO_LAnd:
case BO_LOr:
if (checkEitherSide(BO, isUnaryLNot))
return true;
if (NestingLevel) {
if (checkEitherSide(BO, [NestingLevel](const Expr *E) {
return nestedDemorgan(E, NestingLevel - 1);
}))
return true;
}
return false;
return checkEitherSide(
BO,
[this](const Expr *E) { return isExpectedUnaryLNot(E); }) ||
(NestingLevel &&
checkEitherSide(BO, [this, NestingLevel](const Expr *E) {
return nestedDemorgan(E, NestingLevel - 1);
}));
default:
return false;
}
Expand All @@ -556,19 +560,19 @@ class SimplifyBooleanExprCheck::Visitor : public RecursiveASTVisitor<Visitor> {
bool TraverseUnaryOperator(UnaryOperator *Op) {
if (!Check->SimplifyDeMorgan || Op->getOpcode() != UO_LNot)
return Base::TraverseUnaryOperator(Op);
Expr *SubImp = Op->getSubExpr()->IgnoreImplicit();
auto *Parens = dyn_cast<ParenExpr>(SubImp);
auto *BinaryOp =
Parens
? dyn_cast<BinaryOperator>(Parens->getSubExpr()->IgnoreImplicit())
: dyn_cast<BinaryOperator>(SubImp);
if (!BinaryOp || !BinaryOp->isLogicalOp() ||
!BinaryOp->getType()->isBooleanType())
const Expr *SubImp = Op->getSubExpr()->IgnoreImplicit();
const auto *Parens = dyn_cast<ParenExpr>(SubImp);
const Expr *SubExpr =
Parens ? Parens->getSubExpr()->IgnoreImplicit() : SubImp;
if (!isExpectedBinaryOp(SubExpr))
return Base::TraverseUnaryOperator(Op);
const auto *BinaryOp = cast<BinaryOperator>(SubExpr);
if (Check->SimplifyDeMorganRelaxed ||
checkEitherSide(BinaryOp, isUnaryLNot) ||
checkEitherSide(BinaryOp,
[](const Expr *E) { return nestedDemorgan(E, 1); })) {
checkEitherSide(
BinaryOp,
[this](const Expr *E) { return isExpectedUnaryLNot(E); }) ||
checkEitherSide(
BinaryOp, [this](const Expr *E) { return nestedDemorgan(E, 1); })) {
if (Check->reportDeMorgan(Context, Op, BinaryOp, !IsProcessing, parent(),
Parens) &&
!Check->areDiagsSelfContained()) {
Expand Down Expand Up @@ -694,6 +698,10 @@ void SimplifyBooleanExprCheck::check(const MatchFinder::MatchResult &Result) {
Visitor(this, *Result.Context).traverse();
}

bool SimplifyBooleanExprCheck::canBeBypassed(const Stmt *S) const {
return IgnoreMacros && S->getBeginLoc().isMacroID();
}

void SimplifyBooleanExprCheck::issueDiag(const ASTContext &Context,
SourceLocation Loc,
StringRef Description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class SimplifyBooleanExprCheck : public ClangTidyCheck {
StringRef Description, SourceRange ReplacementRange,
StringRef Replacement);

bool canBeBypassed(const Stmt *S) const;

const bool IgnoreMacros;
const bool ChainedConditionalReturn;
const bool ChainedConditionalAssignment;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ void StaticAccessedThroughInstanceCheck::check(

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

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

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

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

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

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

if (getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold)
return;

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

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

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

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

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

namespace clang::tidy::readability {

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

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

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

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

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

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

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

namespace clang::tidy::readability {

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

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

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

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

} // namespace clang::tidy::readability
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@ static bool applyAbbreviationHeuristic(
const llvm::StringMap<std::string> &AbbreviationDictionary, StringRef Arg,
StringRef Param) {
if (AbbreviationDictionary.contains(Arg) &&
Param.equals(AbbreviationDictionary.lookup(Arg)))
Param == AbbreviationDictionary.lookup(Arg))
return true;

if (AbbreviationDictionary.contains(Param) &&
Arg.equals(AbbreviationDictionary.lookup(Param)))
Arg == AbbreviationDictionary.lookup(Param))
return true;

return false;
Expand Down
16 changes: 10 additions & 6 deletions clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,11 @@ static bool castMismatchedIntegerTypes(const CallExpr *Call, bool StrictMode) {
FormatStringConverter::FormatStringConverter(ASTContext *ContextIn,
const CallExpr *Call,
unsigned FormatArgOffset,
bool StrictMode,
const Configuration ConfigIn,
const LangOptions &LO)
: Context(ContextIn),
CastMismatchedIntegerTypes(castMismatchedIntegerTypes(Call, StrictMode)),
: Context(ContextIn), Config(ConfigIn),
CastMismatchedIntegerTypes(
castMismatchedIntegerTypes(Call, ConfigIn.StrictMode)),
Args(Call->getArgs()), NumArgs(Call->getNumArgs()),
ArgsOffset(FormatArgOffset + 1), LangOpts(LO) {
assert(ArgsOffset <= NumArgs);
Expand Down Expand Up @@ -627,9 +628,12 @@ void FormatStringConverter::finalizeFormatText() {

// It's clearer to convert printf("Hello\r\n"); to std::print("Hello\r\n")
// than to std::println("Hello\r");
if (StringRef(StandardFormatString).ends_with("\\n") &&
!StringRef(StandardFormatString).ends_with("\\\\n") &&
!StringRef(StandardFormatString).ends_with("\\r\\n")) {
// Use StringRef until C++20 std::string::ends_with() is available.
const auto StandardFormatStringRef = StringRef(StandardFormatString);
if (Config.AllowTrailingNewlineRemoval &&
StandardFormatStringRef.ends_with("\\n") &&
!StandardFormatStringRef.ends_with("\\\\n") &&
!StandardFormatStringRef.ends_with("\\r\\n")) {
UsePrintNewlineFunction = true;
FormatStringNeededRewriting = true;
StandardFormatString.erase(StandardFormatString.end() - 2,
Expand Down
9 changes: 8 additions & 1 deletion clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,14 @@ class FormatStringConverter
public:
using ConversionSpecifier = clang::analyze_format_string::ConversionSpecifier;
using PrintfSpecifier = analyze_printf::PrintfSpecifier;

struct Configuration {
bool StrictMode = false;
bool AllowTrailingNewlineRemoval = false;
};

FormatStringConverter(ASTContext *Context, const CallExpr *Call,
unsigned FormatArgOffset, bool StrictMode,
unsigned FormatArgOffset, Configuration Config,
const LangOptions &LO);

bool canApply() const { return ConversionNotPossibleReason.empty(); }
Expand All @@ -45,6 +51,7 @@ class FormatStringConverter

private:
ASTContext *Context;
const Configuration Config;
const bool CastMismatchedIntegerTypes;
const Expr *const *Args;
const unsigned NumArgs;
Expand Down
3 changes: 1 addition & 2 deletions clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ determineIncludeKind(StringRef CanonicalFile, StringRef IncludeFile,
if (FileCopy.consume_front(Parts.first) &&
FileCopy.consume_back(Parts.second)) {
// Determine the kind of this inclusion.
if (FileCopy.equals("/internal/") ||
FileCopy.equals("/proto/")) {
if (FileCopy == "/internal/" || FileCopy == "/proto/") {
return IncludeSorter::IK_MainTUInclude;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ static const NamedDecl *findDecl(const RecordDecl &RecDecl,
StringRef DeclName) {
for (const Decl *D : RecDecl.decls()) {
if (const auto *ND = dyn_cast<NamedDecl>(D)) {
if (ND->getDeclName().isIdentifier() && ND->getName().equals(DeclName))
if (ND->getDeclName().isIdentifier() && ND->getName() == DeclName)
return ND;
}
}
Expand Down
4 changes: 3 additions & 1 deletion clang-tools-extra/clangd/Preamble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,9 @@ void PreamblePatch::apply(CompilerInvocation &CI) const {
// no guarantees around using arbitrary options when reusing PCHs, and
// different target opts can result in crashes, see
// ParsedASTTest.PreambleWithDifferentTarget.
CI.TargetOpts = Baseline->TargetOpts;
// Make sure this is a deep copy, as the same Baseline might be used
// concurrently.
*CI.TargetOpts = *Baseline->TargetOpts;

// No need to map an empty file.
if (PatchContents.empty())
Expand Down
39 changes: 38 additions & 1 deletion clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ Improvements to clang-doc
Improvements to clang-query
---------------------------

The improvements are...
- Added the `file` command to dynamically load a list of commands and matchers
from an external file, allowing the cost of reading the compilation database
and building the AST to be imposed just once for faster prototyping.

Improvements to clang-rename
----------------------------
Expand Down Expand Up @@ -148,6 +150,15 @@ New checks
Finds initializer lists for aggregate types that could be
written as designated initializers instead.

- New :doc:`modernize-use-std-format
<clang-tidy/checks/modernize/use-std-format>` check.

Converts calls to ``absl::StrFormat``, or other functions via
configuration options, to C++20's ``std::format``, or another function
via a configuration option, modifying the format string appropriately and
removing now-unnecessary calls to ``std::string::c_str()`` and
``std::string::data()``.

- New :doc:`readability-enum-initial-value
<clang-tidy/checks/readability/enum-initial-value>` check.

Expand Down Expand Up @@ -202,6 +213,10 @@ Changes in existing checks
eliminating false positives resulting from direct usage of bitwise operators
within parentheses.

- Improved :doc:`bugprone-optional-value-conversion
<clang-tidy/checks/bugprone/optional-value-conversion>` check by eliminating
false positives resulting from use of optionals in unevaluated context.

- Improved :doc:`bugprone-suspicious-include
<clang-tidy/checks/bugprone/suspicious-include>` check by replacing the local
options `HeaderFileExtensions` and `ImplementationFileExtensions` by the
Expand Down Expand Up @@ -259,6 +274,10 @@ Changes in existing checks
- Improved :doc:`google-runtime-int <clang-tidy/checks/google/runtime-int>`
check performance through optimizations.

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

- Improved :doc:`hicpp-ignored-remove-result <clang-tidy/checks/hicpp/ignored-remove-result>`
check by ignoring other functions with same prefixes as the target specific
functions.
Expand Down Expand Up @@ -333,6 +352,10 @@ Changes in existing checks
<clang-tidy/checks/readability/duplicate-include>` check by excluding include
directives that form the filename using macro.

- Improved :doc:`readability-else-after-return
<clang-tidy/checks/readability/else-after-return>` check to ignore
`if consteval` statements, for which the `else` branch must not be removed.

- Improved :doc:`readability-identifier-naming
<clang-tidy/checks/readability/identifier-naming>` check in `GetConfigPerFile`
mode by resolving symbolic links to header files. Fixed handling of Hungarian
Expand All @@ -348,11 +371,25 @@ Changes in existing checks
<clang-tidy/checks/readability/redundant-inline-specifier>` check to properly
emit warnings for static data member with an in-class initializer.

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

- Improved :doc:`readability-simplify-boolean-expr
<clang-tidy/checks/readability/simplify-boolean-expr>` check to avoid to emit
warning for macro when IgnoreMacro option is enabled.

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

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

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

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ Clang-Tidy Checks
:doc:`modernize-use-nullptr <modernize/use-nullptr>`, "Yes"
:doc:`modernize-use-override <modernize/use-override>`, "Yes"
:doc:`modernize-use-starts-ends-with <modernize/use-starts-ends-with>`, "Yes"
:doc:`modernize-use-std-format <modernize/use-std-format>`, "Yes"
:doc:`modernize-use-std-numbers <modernize/use-std-numbers>`, "Yes"
:doc:`modernize-use-std-print <modernize/use-std-print>`, "Yes"
:doc:`modernize-use-trailing-return-type <modernize/use-trailing-return-type>`, "Yes"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.. title:: clang-tidy - modernize-use-std-format

modernize-use-std-format
========================

Converts calls to ``absl::StrFormat``, or other functions via
configuration options, to C++20's ``std::format``, or another function
via a configuration option, modifying the format string appropriately and
removing now-unnecessary calls to ``std::string::c_str()`` and
``std::string::data()``.

For example, it turns lines like

.. code-block:: c++

return absl::StrFormat("The %s is %3d", description.c_str(), value);

into:

.. code-block:: c++

return std::format("The {} is {:3}", description, value);

The check uses the same format-string-conversion algorithm as
`modernize-use-std-print <../modernize/use-std-print.html>`_ and its
shortcomings are described in the documentation for that check.

Options
-------

.. option:: StrictMode

When `true`, the check will add casts when converting from variadic
functions and printing signed or unsigned integer types (including
fixed-width integer types from ``<cstdint>``, ``ptrdiff_t``, ``size_t``
and ``ssize_t``) as the opposite signedness to ensure that the output
would matches that of a simple wrapper for ``std::sprintf`` that
accepted a C-style variable argument list. For example, with
`StrictMode` enabled,

.. code-block:: c++

extern std::string strprintf(const char *format, ...);
int i = -42;
unsigned int u = 0xffffffff;
return strprintf("%d %u\n", i, u);
would be converted to

.. code-block:: c++

return std::format("{} {}\n", static_cast<unsigned int>(i), static_cast<int>(u));

to ensure that the output will continue to be the unsigned representation
of -42 and the signed representation of 0xffffffff (often 4294967254
and -1 respectively). When `false` (which is the default), these casts
will not be added which may cause a change in the output. Note that this
option makes no difference for the default value of
`StrFormatLikeFunctions` since ``absl::StrFormat`` takes a function
parameter pack and is not a variadic function.

.. option:: StrFormatLikeFunctions

A semicolon-separated list of (fully qualified) function names to
replace, with the requirement that the first parameter contains the
printf-style format string and the arguments to be formatted follow
immediately afterwards. The default value for this option is
`absl::StrFormat`.

.. option:: ReplacementFormatFunction

The function that will be used to replace the function set by the
`StrFormatLikeFunctions` option rather than the default
`std::format`. It is expected that the function provides an interface
that is compatible with ``std::format``. A suitable candidate would be
`fmt::format`.

.. option:: FormatHeader

The header that must be included for the declaration of
`ReplacementFormatFunction` so that a ``#include`` directive can be added if
required. If `ReplacementFormatFunction` is `std::format` then this option will
default to ``<format>``, otherwise this option will default to nothing
and no ``#include`` directive will be added.
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ is changed to:
C::E1;
C::E2;
The `--fix` commandline option provides default support for safe fixes, whereas
`--fix-notes` enables fixes that may replace expressions with side effects,
potentially altering the program's behavior.
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ recommended to avoid the risk of incorrect interpretation of the return value
and to simplify the code. The string equality and inequality operators can
also be faster than the ``compare`` method due to early termination.

Examples:
Example
-------

.. code-block:: c++

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

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

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

Options
-------

.. option:: StringLikeClasses

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

Example
^^^^^^^

.. code-block:: c++

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

CustomString str1;
CustomString str2;

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

If `StringLikeClasses` contains ``CustomString``, the check will suggest
replacing ``compare`` with equality operator.
1 change: 1 addition & 0 deletions clang-tools-extra/test/clang-query/Inputs/empty.script
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# This file intentionally has no queries
1 change: 1 addition & 0 deletions clang-tools-extra/test/clang-query/Inputs/file.script
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
f DIRECTORY/runtime_file.script
5 changes: 5 additions & 0 deletions clang-tools-extra/test/clang-query/Inputs/runtime_file.script
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
set bind-root false

l func functionDecl(hasName("bar"))
m func.bind("f")
m varDecl().bind("v")
2 changes: 2 additions & 0 deletions clang-tools-extra/test/clang-query/errors.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// RUN: not clang-query -c foo -c bar %s -- | FileCheck %s
// RUN: not clang-query -f %S/Inputs/foo.script %s -- | FileCheck %s
// RUN: not clang-query -f %S/Inputs/nonexistent.script %s -- 2>&1 | FileCheck --check-prefix=CHECK-NONEXISTENT %s
// RUN: not clang-query -c 'file %S/Inputs/nonexistent.script' %s -- 2>&1 | FileCheck --check-prefix=CHECK-NONEXISTENT-FILEQUERY %s
// RUN: not clang-query -c foo -f foo %s -- 2>&1 | FileCheck --check-prefix=CHECK-BOTH %s

// CHECK: unknown command: foo
// CHECK-NOT: unknown command: bar

// CHECK-NONEXISTENT: cannot open {{.*}}nonexistent.script
// CHECK-NONEXISTENT-FILEQUERY: cannot open {{.*}}nonexistent.script
// CHECK-BOTH: cannot specify both -c and -f
2 changes: 2 additions & 0 deletions clang-tools-extra/test/clang-query/file-empty.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// RUN: clang-query -c 'file %S/Inputs/empty.script' %s --
// COM: no output expected; nothing to CHECK
14 changes: 14 additions & 0 deletions clang-tools-extra/test/clang-query/file-query.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: rm -rf %/t
// RUN: mkdir %/t
// RUN: cp %/S/Inputs/file.script %/t/file.script
// RUN: cp %/S/Inputs/runtime_file.script %/t/runtime_file.script
// Need to embed the correct temp path in the actual JSON-RPC requests.
// RUN: sed -e "s|DIRECTORY|%/t|" %/t/file.script > %/t/file.script.temp

// RUN: clang-query -c 'file %/t/file.script.temp' %s -- | FileCheck %s

// CHECK: file-query.c:11:1: note: "f" binds here
void bar(void) {}

// CHECK: file-query.c:14:1: note: "v" binds here
int baz{1};
10 changes: 10 additions & 0 deletions clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ struct basic_string_view {
constexpr bool starts_with(C ch) const noexcept;
constexpr bool starts_with(const C* s) const;

constexpr int compare(basic_string_view sv) const noexcept;

static constexpr size_t npos = -1;
};

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

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

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

size_t strlen(const char* str);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,6 @@ void correct(std::optional<int> param)
std::optional<long>* p2 = &p;
takeOptionalValue(p2->value_or(5U));
takeOptionalRef(p2->value_or(5U));

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

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

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

enum EnumConstruction {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// RUN: %check_clang_tidy -check-suffixes=,STRICT \
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
// RUN: -config="{CheckOptions: { \
// RUN: modernize-use-std-format.StrictMode: true, \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2', \
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \
// RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \
// RUN: }}" \
// RUN: -- -isystem %clang_tidy_headers
// RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
// RUN: -config="{CheckOptions: { \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2', \
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \
// RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \
// RUN: }}" \
// RUN: -- -isystem %clang_tidy_headers

#include <cstdio>
#include <string>
// CHECK-FIXES: #include <fmt/core.h>

std::string strprintf(const char *, ...);

namespace mynamespace {
std::string strprintf2(const char *, ...);
}

std::string strprintf_test(const std::string &name, double value) {
return strprintf("'%s'='%f'\n", name.c_str(), value);
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'fmt::format' instead of 'strprintf' [modernize-use-std-format]
// CHECK-FIXES: return fmt::format("'{}'='{:f}'\n", name, value);

return mynamespace::strprintf2("'%s'='%f'\n", name.c_str(), value);
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'fmt::format' instead of 'strprintf2' [modernize-use-std-format]
// CHECK-FIXES: return fmt::format("'{}'='{:f}'\n", name, value);
}

std::string StrFormat_strict_conversion() {
const unsigned char uc = 'A';
return strprintf("Integer %hhd from unsigned char\n", uc);
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'fmt::format' instead of 'strprintf' [modernize-use-std-format]
// CHECK-FIXES-NOTSTRICT: return fmt::format("Integer {} from unsigned char\n", uc);
// CHECK-FIXES-STRICT: return fmt::format("Integer {} from unsigned char\n", static_cast<signed char>(uc));
}

// Ensure that MatchesAnyListedNameMatcher::NameMatcher::match() can cope with a
// NamedDecl that has no name when we're trying to match unqualified_strprintf.
std::string A(const std::string &in)
{
return "_" + in;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %check_clang_tidy %s modernize-use-std-format %t -- \
// RUN: -config="{CheckOptions: { \
// RUN: StrictMode: true, \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: 'fmt::sprintf', \
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \
// RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \
// RUN: }}" \
// RUN: -- -isystem %clang_tidy_headers

// CHECK-FIXES: #include <fmt/core.h>
#include <string>

namespace fmt
{
// Use const char * for the format since the real type is hard to mock up.
template <typename... Args>
std::string sprintf(const char *format, const Args&... args);
} // namespace fmt

std::string fmt_sprintf_simple() {
return fmt::sprintf("Hello %s %d", "world", 42);
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'fmt::format' instead of 'sprintf' [modernize-use-std-format]
// CHECK-FIXES: fmt::format("Hello {} {}", "world", 42);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// RUN: %check_clang_tidy \
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
// RUN: -config="{CheckOptions: {StrictMode: true}}" \
// RUN: -- -isystem %clang_tidy_headers
// RUN: %check_clang_tidy \
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
// RUN: -config="{CheckOptions: {StrictMode: false}}" \
// RUN: -- -isystem %clang_tidy_headers
#include <string>
// CHECK-FIXES: #include <format>

namespace absl
{
// Use const char * for the format since the real type is hard to mock up.
template <typename... Args>
std::string StrFormat(const char *format, const Args&... args);
} // namespace absl

template <typename T>
struct iterator {
T *operator->();
T &operator*();
};

std::string StrFormat_simple() {
return absl::StrFormat("Hello");
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: return std::format("Hello");
}

std::string StrFormat_complex(const char *name, double value) {
return absl::StrFormat("'%s'='%f'", name, value);
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);
}

std::string StrFormat_integer_conversions() {
return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B');
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');
}

// FormatConverter is capable of removing newlines from the end of the format
// string. Ensure that isn't incorrectly happening for std::format.
std::string StrFormat_no_newline_removal() {
return absl::StrFormat("a line\n");
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: return std::format("a line\n");
}

// FormatConverter is capable of removing newlines from the end of the format
// string. Ensure that isn't incorrectly happening for std::format.
std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {
return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data());
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);
}

std::string StrFormat_strict_conversion() {
const unsigned char uc = 'A';
return absl::StrFormat("Integer %hhd from unsigned char\n", uc);
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);
}

std::string StrFormat_field_width_and_precision() {
auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);

auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2);
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: std::format("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);

const int width = 10, precision = 3;
const unsigned int ui1 = 42, ui2 = 43, ui3 = 44;
auto s3 = absl::StrFormat("casts width only:%*d width and precision:%*.*d precision only:%.*d\n", 3, ui1, 4, 2, ui2, 5, ui3);
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES-NOTSTRICT: std::format("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", ui1, 3, ui2, 4, 2, ui3, 5);
// CHECK-FIXES-STRICT: std::format("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", static_cast<int>(ui1), 3, static_cast<int>(ui2), 4, 2, static_cast<int>(ui3), 5);

auto s4 = absl::StrFormat("c_str removal width only:%*s width and precision:%*.*s precision only:%.*s", 3, s1.c_str(), 4, 2, s2.c_str(), 5, s3.c_str());
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: std::format("c_str removal width only:{:>{}} width and precision:{:>{}.{}} precision only:{:.{}}", s1, 3, s2, 4, 2, s3, 5);

const std::string *ps1 = &s1, *ps2 = &s2, *ps3 = &s3;
auto s5 = absl::StrFormat("c_str() removal pointer width only:%-*s width and precision:%-*.*s precision only:%-.*s", 3, ps1->c_str(), 4, 2, ps2->c_str(), 5, ps3->c_str());
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: std::format("c_str() removal pointer width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *ps1, 3, *ps2, 4, 2, *ps3, 5);

iterator<std::string> is1, is2, is3;
auto s6 = absl::StrFormat("c_str() removal iterator width only:%-*s width and precision:%-*.*s precision only:%-.*s", 3, is1->c_str(), 4, 2, is2->c_str(), 5, is3->c_str());
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: std::format("c_str() removal iterator width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *is1, 3, *is2, 4, 2, *is3, 5);

return s1 + s2 + s3 + s4 + s5 + s6;
}

std::string StrFormat_macros() {
// The function call is replaced even though it comes from a macro.
#define FORMAT absl::StrFormat
auto s1 = FORMAT("Hello %d", 42);
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: std::format("Hello {}", 42);

// The format string is replaced even though it comes from a macro, this
// behaviour is required so that that <inttypes.h> macros are replaced.
#define FORMAT_STRING "Hello %s"
auto s2 = absl::StrFormat(FORMAT_STRING, 42);
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: std::format("Hello {}", 42);

// Arguments that are macros aren't replaced with their value, even if they are rearranged.
#define VALUE 3.14159265358979323846
#define WIDTH 10
#define PRECISION 4
auto s3 = absl::StrFormat("Hello %*.*f", WIDTH, PRECISION, VALUE);
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
// CHECK-FIXES: std::format("Hello {:{}.{}f}", VALUE, WIDTH, PRECISION);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: %check_clang_tidy -std=c++23 %s readability-else-after-return %t

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

if consteval {
return;
} else {
return;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,25 @@
// RUN: --

#define NEGATE(expr) !(expr)
#define NOT_AND_NOT(a, b) (!a && !b)

bool without_macro(bool a, bool b) {
return !(!a && b);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: boolean expression can be simplified by DeMorgan's theorem
// CHECK-FIXES: return a || !b;
}

bool macro(bool a, bool b) {
return NEGATE(!a && b);
// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:12: warning: boolean expression can be simplified by DeMorgan's theorem
// CHECK-FIXES: return NEGATE(!a && b);
void macro(bool a, bool b) {
NEGATE(!a && b);
// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:5: warning: boolean expression can be simplified by DeMorgan's theorem
// CHECK-FIXES: NEGATE(!a && b);
!NOT_AND_NOT(a, b);
// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:5: warning: boolean expression can be simplified by DeMorgan's theorem
// CHECK-FIXES: !NOT_AND_NOT(a, b);
!(NEGATE(a) && b);
// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:5: warning: boolean expression can be simplified by DeMorgan's theorem
// CHECK-FIXES: !(NEGATE(a) && b);
!(a && NEGATE(b));
// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:5: warning: boolean expression can be simplified by DeMorgan's theorem
// CHECK-FIXES: !(a && NEGATE(b));
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- -- -isystem %S/Inputs/static-accessed-through-instance
// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- --fix-notes -- -isystem %S/Inputs/static-accessed-through-instance
#include <__clang_cuda_builtin_vars.h>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

struct DerivedFromStdString : std::string {};

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

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

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

std::string_view sv1("a");
std::string_view sv2("b");
if (sv1 == sv2) {
}
if (sv1.compare(sv2) > 0) {
}
}
4 changes: 3 additions & 1 deletion clang-tools-extra/unittests/clang-query/QueryParserTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ TEST_F(QueryParserTest, Comment) {
TEST_F(QueryParserTest, Complete) {
std::vector<llvm::LineEditor::Completion> Comps =
QueryParser::complete("", 0, QS);
ASSERT_EQ(8u, Comps.size());
ASSERT_EQ(9u, Comps.size());
EXPECT_EQ("help ", Comps[0].TypedText);
EXPECT_EQ("help", Comps[0].DisplayText);
EXPECT_EQ("let ", Comps[1].TypedText);
Expand All @@ -214,6 +214,8 @@ TEST_F(QueryParserTest, Complete) {
EXPECT_EQ("disable", Comps[6].DisplayText);
EXPECT_EQ("unlet ", Comps[7].TypedText);
EXPECT_EQ("unlet", Comps[7].DisplayText);
EXPECT_EQ("file ", Comps[8].TypedText);
EXPECT_EQ("file", Comps[8].DisplayText);

Comps = QueryParser::complete("set o", 5, QS);
ASSERT_EQ(1u, Comps.size());
Expand Down
2 changes: 2 additions & 0 deletions clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ endif()


if( CLANG_INCLUDE_TESTS )
find_package(Perl)

add_subdirectory(unittests)
list(APPEND CLANG_TEST_DEPS ClangUnitTests)
list(APPEND CLANG_TEST_PARAMS
Expand Down
2 changes: 1 addition & 1 deletion clang/docs/Block-ABI-Apple.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ The following flags bits are in use thusly for a possible ABI.2010.3.16:
In 10.6.ABI the (1<<29) was usually set and was always ignored by the runtime -
it had been a transitional marker that did not get deleted after the
transition. This bit is now paired with (1<<30), and represented as the pair
(3<<30), for the following combinations of valid bit settings, and their
(3<<29), for the following combinations of valid bit settings, and their
meanings:

.. code-block:: c
Expand Down
12 changes: 10 additions & 2 deletions clang/docs/ClangOffloadBundler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ Where:
object as a data section with the name ``.hip_fatbin``.

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

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

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

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

Expand Down
5 changes: 4 additions & 1 deletion clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1662,8 +1662,11 @@ The following type trait primitives are supported by Clang. Those traits marked
``T`` from ``U`` is ill-formed.
Deprecated, use ``__reference_constructs_from_temporary``.
* ``__reference_constructs_from_temporary(T, U)`` (C++)
Returns true if a reference ``T`` can be constructed from a temporary of type
Returns true if a reference ``T`` can be direct-initialized from a temporary of type
a non-cv-qualified ``U``.
* ``__reference_converts_from_temporary(T, U)`` (C++)
Returns true if a reference ``T`` can be copy-initialized from a temporary of type
a non-cv-qualified ``U``.
* ``__underlying_type`` (C++, GNU, Microsoft)

In addition, the following expression traits are supported:
Expand Down
12 changes: 12 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ C++23 Feature Support

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

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

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

Expand Down Expand Up @@ -699,6 +702,14 @@ Bug Fixes to C++ Support
performed incorrectly when checking constraints. Fixes (#GH90349).
- Clang now allows constrained member functions to be explicitly specialized for an implicit instantiation
of a class template.
- Fix a C++23 bug in implementation of P2564R3 which evaluates immediate invocations in place
within initializers for variables that are usable in constant expressions or are constant
initialized, rather than evaluating them as a part of the larger manifestly constant evaluated
expression.
- Fix a bug in access control checking due to dealyed checking of friend declaration. Fixes (#GH12361).
- Correctly treat the compound statement of an ``if consteval`` as an immediate context. Fixes (#GH91509).
- When partial ordering alias templates against template template parameters,
allow pack expansions when the alias has a fixed-size parameter list. Fixes (#GH62529).

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

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

AIX Support
^^^^^^^^^^^
Expand Down
1,215 changes: 604 additions & 611 deletions clang/docs/StandardCPlusPlusModules.rst

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion clang/docs/tools/clang-formatted-files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -632,11 +632,12 @@ clang/unittests/Analysis/FlowSensitive/MapLatticeTest.cpp
clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp
clang/unittests/Analysis/FlowSensitive/MultiVarConstantPropagationTest.cpp
clang/unittests/Analysis/FlowSensitive/SingleVarConstantPropagationTest.cpp
clang/unittests/Analysis/FlowSensitive/SolverTest.cpp
clang/unittests/Analysis/FlowSensitive/SolverTest.h
clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
clang/unittests/Analysis/FlowSensitive/WatchedLiteralsSolverTest.cpp
clang/unittests/AST/ASTImporterFixtures.cpp
clang/unittests/AST/ASTImporterFixtures.h
clang/unittests/AST/ASTImporterObjCTest.cpp
Expand Down
175 changes: 173 additions & 2 deletions clang/include/clang/AST/OpenACCClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "clang/AST/StmtIterator.h"
#include "clang/Basic/OpenACCKinds.h"

#include <utility>

namespace clang {
/// This is the base type for all OpenACC Clauses.
class OpenACCClause {
Expand All @@ -26,14 +28,17 @@ class OpenACCClause {
protected:
OpenACCClause(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation EndLoc)
: Kind(K), Location(BeginLoc, EndLoc) {}
: Kind(K), Location(BeginLoc, EndLoc) {
assert(!BeginLoc.isInvalid() && !EndLoc.isInvalid() &&
"Begin and end location must be valid for OpenACCClause");
}

public:
OpenACCClauseKind getClauseKind() const { return Kind; }
SourceLocation getBeginLoc() const { return Location.getBegin(); }
SourceLocation getEndLoc() const { return Location.getEnd(); }

static bool classof(const OpenACCClause *) { return true; }
static bool classof(const OpenACCClause *) { return false; }

using child_iterator = StmtIterator;
using const_child_iterator = ConstStmtIterator;
Expand All @@ -60,6 +65,8 @@ class OpenACCClauseWithParams : public OpenACCClause {
: OpenACCClause(K, BeginLoc, EndLoc), LParenLoc(LParenLoc) {}

public:
static bool classof(const OpenACCClause *C);

SourceLocation getLParenLoc() const { return LParenLoc; }

child_range children() {
Expand All @@ -70,6 +77,63 @@ class OpenACCClauseWithParams : public OpenACCClause {
}
};

using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
/// A 'device_type' or 'dtype' clause, takes a list of either an 'asterisk' or
/// an identifier. The 'asterisk' means 'the rest'.
class OpenACCDeviceTypeClause final
: public OpenACCClauseWithParams,
public llvm::TrailingObjects<OpenACCDeviceTypeClause,
DeviceTypeArgument> {
// Data stored in trailing objects as IdentifierInfo* /SourceLocation pairs. A
// nullptr IdentifierInfo* represents an asterisk.
unsigned NumArchs;
OpenACCDeviceTypeClause(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc,
ArrayRef<DeviceTypeArgument> Archs,
SourceLocation EndLoc)
: OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc),
NumArchs(Archs.size()) {
assert(
(K == OpenACCClauseKind::DeviceType || K == OpenACCClauseKind::DType) &&
"Invalid clause kind for device-type");

assert(!llvm::any_of(Archs, [](const DeviceTypeArgument &Arg) {
return Arg.second.isInvalid();
}) && "Invalid SourceLocation for an argument");

assert(
(Archs.size() == 1 || !llvm::any_of(Archs,
[](const DeviceTypeArgument &Arg) {
return Arg.first == nullptr;
})) &&
"Only a single asterisk version is permitted, and must be the "
"only one");

std::uninitialized_copy(Archs.begin(), Archs.end(),
getTrailingObjects<DeviceTypeArgument>());
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::DType ||
C->getClauseKind() == OpenACCClauseKind::DeviceType;
}
bool hasAsterisk() const {
return getArchitectures().size() > 0 &&
getArchitectures()[0].first == nullptr;
}

ArrayRef<DeviceTypeArgument> getArchitectures() const {
return ArrayRef<DeviceTypeArgument>(
getTrailingObjects<DeviceTypeArgument>(), NumArchs);
}

static OpenACCDeviceTypeClause *
Create(const ASTContext &C, OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, ArrayRef<DeviceTypeArgument> Archs,
SourceLocation EndLoc);
};

/// A 'default' clause, has the optional 'none' or 'present' argument.
class OpenACCDefaultClause : public OpenACCClauseWithParams {
friend class ASTReaderStmt;
Expand All @@ -89,6 +153,9 @@ class OpenACCDefaultClause : public OpenACCClauseWithParams {
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Default;
}
OpenACCDefaultClauseKind getDefaultClauseKind() const {
return DefaultClauseKind;
}
Expand All @@ -113,6 +180,8 @@ class OpenACCClauseWithCondition : public OpenACCClauseWithParams {
ConditionExpr(ConditionExpr) {}

public:
static bool classof(const OpenACCClause *C);

bool hasConditionExpr() const { return ConditionExpr; }
const Expr *getConditionExpr() const { return ConditionExpr; }
Expr *getConditionExpr() { return ConditionExpr; }
Expand Down Expand Up @@ -140,6 +209,9 @@ class OpenACCIfClause : public OpenACCClauseWithCondition {
Expr *ConditionExpr, SourceLocation EndLoc);

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::If;
}
static OpenACCIfClause *Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *ConditionExpr,
SourceLocation EndLoc);
Expand All @@ -151,6 +223,9 @@ class OpenACCSelfClause : public OpenACCClauseWithCondition {
Expr *ConditionExpr, SourceLocation EndLoc);

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Self;
}
static OpenACCSelfClause *Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc,
Expr *ConditionExpr, SourceLocation EndLoc);
Expand All @@ -177,6 +252,7 @@ class OpenACCClauseWithExprs : public OpenACCClauseWithParams {
llvm::ArrayRef<Expr *> getExprs() const { return Exprs; }

public:
static bool classof(const OpenACCClause *C);
child_range children() {
return child_range(reinterpret_cast<Stmt **>(Exprs.begin()),
reinterpret_cast<Stmt **>(Exprs.end()));
Expand All @@ -189,6 +265,49 @@ class OpenACCClauseWithExprs : public OpenACCClauseWithParams {
}
};

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

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Wait;
}
static OpenACCWaitClause *Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *DevNumExpr,
SourceLocation QueuesLoc,
ArrayRef<Expr *> QueueIdExprs,
SourceLocation EndLoc);

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

class OpenACCNumGangsClause final
: public OpenACCClauseWithExprs,
public llvm::TrailingObjects<OpenACCNumGangsClause, Expr *> {
Expand All @@ -203,6 +322,9 @@ class OpenACCNumGangsClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::NumGangs;
}
static OpenACCNumGangsClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc);
Expand Down Expand Up @@ -232,6 +354,7 @@ class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs {
}

public:
static bool classof(const OpenACCClause *C);
bool hasIntExpr() const { return !getExprs().empty(); }
const Expr *getIntExpr() const {
return hasIntExpr() ? getExprs()[0] : nullptr;
Expand All @@ -245,6 +368,9 @@ class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr {
Expr *IntExpr, SourceLocation EndLoc);

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::NumWorkers;
}
static OpenACCNumWorkersClause *Create(const ASTContext &C,
SourceLocation BeginLoc,
SourceLocation LParenLoc,
Expand All @@ -256,6 +382,9 @@ class OpenACCVectorLengthClause : public OpenACCClauseWithSingleIntExpr {
Expr *IntExpr, SourceLocation EndLoc);

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::VectorLength;
}
static OpenACCVectorLengthClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *IntExpr, SourceLocation EndLoc);
Expand All @@ -266,6 +395,9 @@ class OpenACCAsyncClause : public OpenACCClauseWithSingleIntExpr {
Expr *IntExpr, SourceLocation EndLoc);

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Async;
}
static OpenACCAsyncClause *Create(const ASTContext &C,
SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *IntExpr,
Expand All @@ -283,6 +415,7 @@ class OpenACCClauseWithVarList : public OpenACCClauseWithExprs {
: OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc) {}

public:
static bool classof(const OpenACCClause *C);
ArrayRef<Expr *> getVarList() { return getExprs(); }
ArrayRef<Expr *> getVarList() const { return getExprs(); }
};
Expand All @@ -301,6 +434,9 @@ class OpenACCPrivateClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Private;
}
static OpenACCPrivateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
Expand All @@ -320,6 +456,9 @@ class OpenACCFirstPrivateClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::FirstPrivate;
}
static OpenACCFirstPrivateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
Expand All @@ -339,6 +478,9 @@ class OpenACCDevicePtrClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::DevicePtr;
}
static OpenACCDevicePtrClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
Expand All @@ -358,6 +500,9 @@ class OpenACCAttachClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Attach;
}
static OpenACCAttachClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
Expand All @@ -377,6 +522,9 @@ class OpenACCNoCreateClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::NoCreate;
}
static OpenACCNoCreateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
Expand All @@ -396,6 +544,9 @@ class OpenACCPresentClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Present;
}
static OpenACCPresentClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
Expand All @@ -419,6 +570,11 @@ class OpenACCCopyClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Copy ||
C->getClauseKind() == OpenACCClauseKind::PCopy ||
C->getClauseKind() == OpenACCClauseKind::PresentOrCopy;
}
static OpenACCCopyClause *
Create(const ASTContext &C, OpenACCClauseKind Spelling,
SourceLocation BeginLoc, SourceLocation LParenLoc,
Expand All @@ -445,6 +601,11 @@ class OpenACCCopyInClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::CopyIn ||
C->getClauseKind() == OpenACCClauseKind::PCopyIn ||
C->getClauseKind() == OpenACCClauseKind::PresentOrCopyIn;
}
bool isReadOnly() const { return IsReadOnly; }
static OpenACCCopyInClause *
Create(const ASTContext &C, OpenACCClauseKind Spelling,
Expand Down Expand Up @@ -472,6 +633,11 @@ class OpenACCCopyOutClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::CopyOut ||
C->getClauseKind() == OpenACCClauseKind::PCopyOut ||
C->getClauseKind() == OpenACCClauseKind::PresentOrCopyOut;
}
bool isZero() const { return IsZero; }
static OpenACCCopyOutClause *
Create(const ASTContext &C, OpenACCClauseKind Spelling,
Expand Down Expand Up @@ -499,6 +665,11 @@ class OpenACCCreateClause final
}

public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Create ||
C->getClauseKind() == OpenACCClauseKind::PCreate ||
C->getClauseKind() == OpenACCClauseKind::PresentOrCreate;
}
bool isZero() const { return IsZero; }
static OpenACCCreateClause *
Create(const ASTContext &C, OpenACCClauseKind Spelling,
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/StmtOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt {
}

public:
static bool classof(const Stmt *T) {
return false;
}

child_range children() {
if (getAssociatedStmt())
return child_range(&AssociatedStmt, &AssociatedStmt + 1);
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -4415,6 +4415,18 @@ def HLSLResourceBinding: InheritableAttr {
let Documentation = [HLSLResourceBindingDocs];
}

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

def HLSLSV_DispatchThreadID: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"SV_DispatchThreadID">];
let Subjects = SubjectList<[ParmVar, Field]>;
Expand Down
20 changes: 20 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -7408,6 +7408,26 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo
}];
}

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

Examples:

.. code-block:: c++

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

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

def HLSLSV_DispatchThreadIDDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/BuiltinsNVPTX.def
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@
#pragma push_macro("PTX81")
#pragma push_macro("PTX82")
#pragma push_macro("PTX83")
#define PTX83 "ptx83"
#pragma push_macro("PTX84")
#define PTX84 "ptx84"
#define PTX83 "ptx83|" PTX84
#define PTX82 "ptx82|" PTX83
#define PTX81 "ptx81|" PTX82
#define PTX80 "ptx80|" PTX81
Expand Down Expand Up @@ -1091,3 +1093,4 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78))
#pragma pop_macro("PTX81")
#pragma pop_macro("PTX82")
#pragma pop_macro("PTX83")
#pragma pop_macro("PTX84")
1 change: 1 addition & 0 deletions clang/include/clang/Basic/BuiltinsWebAssembly.def
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4, "V4fV8UsV8UsV4f"

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

// Reference Types builtins
// Some builtins are custom type-checked - see 't' as part of the third argument,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ CODEGENOPT(UnrollLoops , 1, 0) ///< Control whether loops are unrolled.
CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled.
CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled.
VALUE_CODEGENOPT(UnwindTables, 2, 0) ///< Unwind tables (1) or asynchronous unwind tables (2)
CODEGENOPT(LinkBitcodePostopt, 1, 0) ///< Link builtin bitcodes after optimization pipeline.
CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer.
CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer.
CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate.
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/Cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ enum class CudaVersion {
CUDA_121,
CUDA_122,
CUDA_123,
CUDA_124,
FULLY_SUPPORTED = CUDA_123,
PARTIALLY_SUPPORTED =
CUDA_123, // Partially supported. Proceed with a warning.
CUDA_124, // Partially supported. Proceed with a warning.
NEW = 10000, // Too new. Issue a warning, but allow using it.
};
const char *CudaVersionToString(CudaVersion V);
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,9 @@ def BranchProtection : DiagGroup<"branch-protection">;
// Warnings for HLSL Clang extensions
def HLSLExtension : DiagGroup<"hlsl-extensions">;

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

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

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def err_unsupported_vendor : Error<"vendor '%0' is not supported: '%1'">;
def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'">;
def err_unsupported_os : Error<"os '%0' is not supported: '%1'">;
def err_cannot_read_input_list : Error<"could not read %select{alias list|filelist}0 '%1': %2">;
def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X<label>">;
} // end of command line category.

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

} // end of Parser diagnostics
15 changes: 9 additions & 6 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10035,12 +10035,6 @@ def warn_new_dangling_initializer_list : Warning<
"the allocated initializer list}0 "
"will be destroyed at the end of the full-expression">,
InGroup<DanglingInitializerList>;
def warn_unsupported_lifetime_extension : Warning<
"lifetime extension of "
"%select{temporary|backing array of initializer list}0 created "
"by aggregate initialization using a default member initializer "
"is not yet supported; lifetime of %select{temporary|backing array}0 "
"will end at the end of the full-expression">, InGroup<Dangling>;

// For non-floating point, expressions of the form x == x or x != x
// should result in a warning, since these always evaluate to a constant.
Expand Down Expand Up @@ -12184,6 +12178,11 @@ def err_hlsl_init_priority_unsupported : Error<
def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
def warn_hlsl_packoffset_mix : Warning<"cannot mix packoffset elements with nonpackoffset elements in a cbuffer">,
InGroup<HLSLMixPackOffset>;
def err_hlsl_packoffset_overlap : Error<"packoffset overlap between %0, %1">;
def err_hlsl_packoffset_cross_reg_boundary : Error<"packoffset cannot cross register boundary">;
def err_hlsl_packoffset_alignment_mismatch : Error<"packoffset at 'y' not match alignment %0 required by %1">;
def err_hlsl_pointers_unsupported : Error<
"%select{pointers|references}0 are unsupported in HLSL">;

Expand Down Expand Up @@ -12345,4 +12344,8 @@ def warn_acc_deprecated_alias_name
def err_acc_var_not_pointer_type
: Error<"expected pointer in '%0' clause, type is %1">;
def note_acc_expected_pointer_var : Note<"expected variable of pointer type">;
def err_acc_clause_after_device_type
: Error<"OpenACC clause '%0' may not follow a '%1' clause in a "
"compute construct">;

} // end of sema component.
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
EXTENSION(swiftcc,
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
clang::TargetInfo::CCCR_OK)
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/IdentifierTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ class IdentifierTable {
II->Entry = &Entry;

// If this is the 'import' contextual keyword, mark it as such.
if (Name.equals("import"))
if (Name == "import")
II->setModulesImport(true);

return *II;
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template t
LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features")

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

LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/OpenACCClauses.def
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ CLAUSE_ALIAS(PCreate, Create)
CLAUSE_ALIAS(PresentOrCreate, Create)
VISIT_CLAUSE(Default)
VISIT_CLAUSE(DevicePtr)
VISIT_CLAUSE(DeviceType)
CLAUSE_ALIAS(DType, DeviceType)
VISIT_CLAUSE(FirstPrivate)
VISIT_CLAUSE(If)
VISIT_CLAUSE(NoCreate)
Expand All @@ -46,6 +48,7 @@ VISIT_CLAUSE(Present)
VISIT_CLAUSE(Private)
VISIT_CLAUSE(Self)
VISIT_CLAUSE(VectorLength)
VISIT_CLAUSE(Wait)

#undef VISIT_CLAUSE
#undef CLAUSE_ALIAS
6 changes: 3 additions & 3 deletions clang/include/clang/Basic/SourceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -1504,7 +1504,7 @@ class SourceManager : public RefCountedBase<SourceManager> {
if (Presumed.isInvalid())
return false;
StringRef Filename(Presumed.getFilename());
return Filename.equals("<built-in>");
return Filename == "<built-in>";
}

/// Returns whether \p Loc is located in a <command line> file.
Expand All @@ -1513,7 +1513,7 @@ class SourceManager : public RefCountedBase<SourceManager> {
if (Presumed.isInvalid())
return false;
StringRef Filename(Presumed.getFilename());
return Filename.equals("<command line>");
return Filename == "<command line>";
}

/// Returns whether \p Loc is located in a <scratch space> file.
Expand All @@ -1522,7 +1522,7 @@ class SourceManager : public RefCountedBase<SourceManager> {
if (Presumed.isInvalid())
return false;
StringRef Filename(Presumed.getFilename());
return Filename.equals("<scratch space>");
return Filename == "<scratch space>";
}

/// Returns if a SourceLocation is in a system header.
Expand Down
20 changes: 20 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ struct TransferrableTargetInfo {
unsigned char LongLongWidth, LongLongAlign;
unsigned char Int128Align;

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

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

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

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

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

// Embarcadero Expression Traits
EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX)
Expand Down
Loading