379 changes: 269 additions & 110 deletions bolt/lib/Rewrite/RewriteInstance.cpp

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

// RUN: %clang %cflags -g -Wl,-q -o %t %s

/// Verify that the binary indeed contains an unnamed symbol at _start
/// Verify that the binary indeed contains a fake label ".L0 " at _start.
// RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=CHECK-ELF
// CHECK-ELF-DAG: [[#%x,START:]] {{.*}} FUNC GLOBAL DEFAULT [[#%d,SECTION:]] _start{{$}}
// CHECK-ELF-DAG: [[#%x,START]] {{.*}} NOTYPE LOCAL DEFAULT [[#SECTION]] {{$}}
// CHECK-ELF-DAG: [[#%x,START]] {{.*}} NOTYPE LOCAL DEFAULT [[#SECTION]] .L0 {{$}}

/// Verify that BOLT did not create an extra entry point for the unnamed symbol
/// Verify that BOLT did not create an extra entry point for the fake label.
// RUN: llvm-bolt -o %t.bolt %t --print-cfg | FileCheck %s
// CHECK: Binary Function "_start" after building cfg {
// CHECK: IsMultiEntry: 0
Expand Down
1 change: 1 addition & 0 deletions bolt/test/X86/cdsplit-symbol-names.s
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# RUN: --call-scale=2 --data=%t.fdata --reorder-blocks=ext-tsp
# RUN: llvm-objdump --syms %t.bolt | FileCheck %s --check-prefix=CHECK-SYMS-WARM

# CHECK-SYMS-WARM: 0000000000000000 l df *ABS* 0000000000000000 bolt-pseudo.o
# CHECK-SYMS-WARM: .text.warm
# CHECK-SYMS-WARM-SAME: chain.warm
# CHECK-SYMS-WARM: .text.cold
Expand Down
54 changes: 44 additions & 10 deletions bolt/test/X86/fragment-lite.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,42 @@
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/baz.s -o %t.baz.o
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/baz2.s -o %t.baz2.o
# RUN: link_fdata %s %t.o %t.main.fdata
# RUN: link_fdata %s %t.baz.o %t.baz.fdata
# RUN: merge-fdata %t.main.fdata %t.baz.fdata > %t.fdata
# RUN: %clang %cflags %t.o %t.baz.o -o %t.exe -Wl,-q
# RUN: link_fdata %s %t.baz2.o %t.baz2.fdata
# RUN: merge-fdata %t.main.fdata %t.baz.fdata %t.baz2.fdata > %t.fdata
# RUN: %clang %cflags %t.o %t.baz.o %t.baz2.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.out --lite=1 --data %t.fdata -v=1 -print-cfg \
# RUN: 2>&1 | FileCheck %s

# CHECK: BOLT-INFO: processing main.cold.1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing foo.cold.1/1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing bar.cold.1/1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing foo.cold.1/1(*2) as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing bar.cold.1/1(*2) as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing baz.cold.1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing baz.cold.1/1 as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing baz.cold.1/1(*2) as a sibling of non-ignored function
# CHECK: BOLT-INFO: processing baz.cold.1/2(*2) as a sibling of non-ignored function

# CHECK: Binary Function "main.cold.1" after building cfg
# CHECK: Parent : main

# CHECK: Binary Function "foo.cold.1/1" after building cfg
# CHECK: Binary Function "foo.cold.1/1(*2)" after building cfg
# CHECK: Parent : foo

# CHECK: Binary Function "bar.cold.1/1" after building cfg
# CHECK: Parent : bar/1
# CHECK: Binary Function "bar.cold.1/1(*2)" after building cfg
# CHECK: Parent : bar/1(*2)

# CHECK: Binary Function "baz.cold.1" after building cfg
# CHECK: Parent : baz{{$}}

# CHECK: Binary Function "baz.cold.1/1" after building cfg
# CHECK: Parent : baz/1
# CHECK: Binary Function "baz.cold.1/1(*2)" after building cfg
# CHECK: Parent : baz/1(*2)

# CHECK: Binary Function "baz.cold.1/2(*2)" after building cfg
# CHECK: Parent : baz/2(*2)

#--- main.s
.file "main.s"
.globl main
.type main, %function
main:
Expand Down Expand Up @@ -126,6 +133,7 @@ baz.cold.1:
.size baz.cold.1, .-baz.cold.1

#--- baz.s
.file "baz.s"
.local baz
.type baz, %function
baz:
Expand All @@ -149,3 +157,29 @@ baz.cold.1:
retq
.cfi_endproc
.size baz.cold.1, .-baz.cold.1

#--- baz2.s
.file "baz2.s"
.local baz
.type baz, %function
baz:
.cfi_startproc
# FDATA: 0 [unknown] 0 1 baz/2 0 1 0
cmpl $0x0, %eax
je baz.cold.1
retq
.cfi_endproc
.size baz, .-baz

.section .text.cold
.local baz.cold.1
.type baz.cold.1, %function
baz.cold.1:
.cfi_startproc
pushq %rbp
movq %rsp, %rbp
movl $0x0, %eax
popq %rbp
retq
.cfi_endproc
.size baz.cold.1, .-baz.cold.1
16 changes: 16 additions & 0 deletions bolt/test/X86/indirect-goto-pie.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Check that llvm-bolt fails to process PIC binaries with computed goto, as the
# support is not there yet for correctly updating dynamic relocations
# referencing code inside functions.

REQUIRES: x86_64-linux

RUN: %clang %S/Inputs/indirect_goto.c -o %t -fpic -pie -Wl,-q
RUN: not llvm-bolt %t -o %t.bolt --relocs=1 --print-cfg --print-only=main \
RUN: |& FileCheck %s

# Check that processing works if main() is skipped.
RUN: llvm-bolt %t -o %t.bolt --relocs=1 --skip-funcs=main

CHECK: jmpq *%rax # UNKNOWN CONTROL FLOW

CHECK: BOLT-ERROR: unable to get new address
9 changes: 8 additions & 1 deletion bolt/test/X86/pre-aggregated-perf.test
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ REQUIRES: system-linux

RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe
RUN: perf2bolt %t.exe -o %t --pa -p %p/Inputs/pre-aggregated.txt -w %t.new \
RUN: --profile-use-dfs
RUN: --profile-use-dfs | FileCheck %s

RUN: llvm-bolt %t.exe -data %t -o %t.null | FileCheck %s
RUN: llvm-bolt %t.exe -data %t.new -o %t.null | FileCheck %s
RUN: llvm-bolt %t.exe -p %p/Inputs/pre-aggregated.txt --pa -o %t.null | FileCheck %s

CHECK: BOLT-INFO: 4 out of 7 functions in the binary (57.1%) have non-empty execution profile

RUN: cat %t | sort | FileCheck %s -check-prefix=PERF2BOLT
RUN: cat %t.new | FileCheck %s -check-prefix=NEWFORMAT

Expand Down
32 changes: 32 additions & 0 deletions bolt/test/X86/register-fragments-bolt-symbols.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Test the heuristics for matching BOLT-added split functions.

# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %S/cdsplit-symbol-names.s -o %t.main.o
# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.chain.o
# RUN: link_fdata %S/cdsplit-symbol-names.s %t.main.o %t.fdata
# RUN: sed -i 's|chain|chain/2|g' %t.fdata
# RUN: llvm-strip --strip-unneeded %t.main.o
# RUN: llvm-objcopy --localize-symbol=chain %t.main.o
# RUN: %clang %cflags %t.chain.o %t.main.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-strategy=randomN \
# RUN: --reorder-blocks=ext-tsp --enable-bat --bolt-seed=7 --data=%t.fdata
# RUN: llvm-objdump --syms %t.bolt | FileCheck %s --check-prefix=CHECK-SYMS

# RUN: link_fdata %s %t.bolt %t.preagg PREAGG
# PREAGG: B X:0 #chain.cold.0# 1 0
# RUN: perf2bolt %t.bolt -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml -v=1 \
# RUN: | FileCheck %s --check-prefix=CHECK-REGISTER

# CHECK-SYMS: l df *ABS* [[#]] chain.s
# CHECK-SYMS: l F .bolt.org.text [[#]] chain
# CHECK-SYMS: l F .text.cold [[#]] chain.cold.0
# CHECK-SYMS: l F .text [[#]] chain
# CHECK-SYMS: l df *ABS* [[#]] bolt-pseudo.o

# CHECK-REGISTER: BOLT-INFO: marking chain.cold.0/1(*2) as a fragment of chain/2(*2)

.file "chain.s"
.text
.type chain, @function
chain:
ret
.size chain, .-chain
2 changes: 1 addition & 1 deletion bolt/test/X86/shrinkwrapping-do-not-pessimize.s
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@ end_if_1:
.size _start, .-_start

.data
rel: .quad end_if_1
rel: .quad _start

# CHECK: BOLT-INFO: Shrink wrapping moved 0 spills inserting load/stores and 0 spills inserting push/pops
18 changes: 0 additions & 18 deletions bolt/test/runtime/X86/Inputs/indirect_goto.c

This file was deleted.

10 changes: 0 additions & 10 deletions bolt/test/runtime/X86/indirect-goto-pie.test

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,8 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
// Get out the qualifiers of the original type. This will always be
// re-applied to the WorkType to ensure it is the same qualification as the
// original From was.
auto QualifiersToApply = From.split().Quals.getAsOpaqueValue();
auto FastQualifiersToApply = static_cast<unsigned>(
From.split().Quals.getAsOpaqueValue() & Qualifiers::FastMask);

// LValue->RValue is irrelevant for the check, because it is a thing to be
// done at a call site, and will be performed if need be performed.
Expand All @@ -993,7 +994,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
// "const double -> double".
LLVM_DEBUG(llvm::dbgs()
<< "--- approximateStdConv. Conversion between numerics.\n");
WorkType = QualType{ToBuiltin, QualifiersToApply};
WorkType = QualType{ToBuiltin, FastQualifiersToApply};
}

const auto *FromEnum = WorkType->getAs<EnumType>();
Expand All @@ -1002,7 +1003,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
// Unscoped enumerations (or enumerations in C) convert to numerics.
LLVM_DEBUG(llvm::dbgs()
<< "--- approximateStdConv. Unscoped enum to numeric.\n");
WorkType = QualType{ToBuiltin, QualifiersToApply};
WorkType = QualType{ToBuiltin, FastQualifiersToApply};
} else if (FromNumeric && ToEnum && ToEnum->isUnscopedEnumerationType()) {
// Numeric types convert to enumerations only in C.
if (Ctx.getLangOpts().CPlusPlus) {
Expand All @@ -1013,7 +1014,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,

LLVM_DEBUG(llvm::dbgs()
<< "--- approximateStdConv. Numeric to unscoped enum.\n");
WorkType = QualType{ToEnum, QualifiersToApply};
WorkType = QualType{ToEnum, FastQualifiersToApply};
}

// Check for pointer conversions.
Expand All @@ -1022,14 +1023,14 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
if (FromPtr && ToPtr) {
if (ToPtr->isVoidPointerType()) {
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. To void pointer.\n");
WorkType = QualType{ToPtr, QualifiersToApply};
WorkType = QualType{ToPtr, FastQualifiersToApply};
}

const auto *FromRecordPtr = FromPtr->getPointeeCXXRecordDecl();
const auto *ToRecordPtr = ToPtr->getPointeeCXXRecordDecl();
if (isDerivedToBase(FromRecordPtr, ToRecordPtr)) {
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived* to Base*\n");
WorkType = QualType{ToPtr, QualifiersToApply};
WorkType = QualType{ToPtr, FastQualifiersToApply};
}
}

Expand All @@ -1039,7 +1040,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
const auto *ToRecord = To->getAsCXXRecordDecl();
if (isDerivedToBase(FromRecord, ToRecord)) {
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived To Base.\n");
WorkType = QualType{ToRecord->getTypeForDecl(), QualifiersToApply};
WorkType = QualType{ToRecord->getTypeForDecl(), FastQualifiersToApply};
}

if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) {
Expand All @@ -1054,7 +1055,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
!ToFunctionPtr->hasNoexceptExceptionSpec()) {
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. noexcept function "
"pointer to non-noexcept.\n");
WorkType = QualType{ToPtr, QualifiersToApply};
WorkType = QualType{ToPtr, FastQualifiersToApply};
}
}

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 @@ -16,6 +16,7 @@ add_clang_library(clangTidyModernizeModule
MakeSharedCheck.cpp
MakeSmartPtrCheck.cpp
MakeUniqueCheck.cpp
MinMaxUseInitializerListCheck.cpp
ModernizeTidyModule.cpp
PassByValueCheck.cpp
RawStringLiteralCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
//===--- MinMaxUseInitializerListCheck.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 "MinMaxUseInitializerListCheck.h"
#include "../utils/ASTUtils.h"
#include "../utils/LexerUtils.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Lexer.h"

using namespace clang;

namespace {

struct FindArgsResult {
const Expr *First;
const Expr *Last;
const Expr *Compare;
SmallVector<const clang::Expr *, 2> Args;
};

} // anonymous namespace

using namespace clang::ast_matchers;

namespace clang::tidy::modernize {

static FindArgsResult findArgs(const CallExpr *Call) {
FindArgsResult Result;
Result.First = nullptr;
Result.Last = nullptr;
Result.Compare = nullptr;

// check if the function has initializer list argument
if (Call->getNumArgs() < 3) {
auto ArgIterator = Call->arguments().begin();

const auto *InitListExpr =
dyn_cast<CXXStdInitializerListExpr>(*ArgIterator);
const auto *InitList =
InitListExpr != nullptr
? dyn_cast<clang::InitListExpr>(
InitListExpr->getSubExpr()->IgnoreImplicit())
: nullptr;

if (InitList) {
Result.Args.append(InitList->inits().begin(), InitList->inits().end());
Result.First = *ArgIterator;
Result.Last = *ArgIterator;

// check if there is a comparison argument
std::advance(ArgIterator, 1);
if (ArgIterator != Call->arguments().end())
Result.Compare = *ArgIterator;

return Result;
}
Result.Args = SmallVector<const Expr *>(Call->arguments());
} else {
// if it has 3 arguments then the last will be the comparison
Result.Compare = *(std::next(Call->arguments().begin(), 2));
Result.Args = SmallVector<const Expr *>(llvm::drop_end(Call->arguments()));
}
Result.First = Result.Args.front();
Result.Last = Result.Args.back();

return Result;
}

static SmallVector<FixItHint>
generateReplacements(const MatchFinder::MatchResult &Match,
const CallExpr *TopCall, const FindArgsResult &Result,
const bool IgnoreNonTrivialTypes,
const std::uint64_t IgnoreTrivialTypesOfSizeAbove) {
SmallVector<FixItHint> FixItHints;
const SourceManager &SourceMngr = *Match.SourceManager;
const LangOptions &LanguageOpts = Match.Context->getLangOpts();

const QualType ResultType = TopCall->getDirectCallee()
->getReturnType()
.getCanonicalType()
.getNonReferenceType()
.getUnqualifiedType();

// check if the type is trivial
const bool IsResultTypeTrivial = ResultType.isTrivialType(*Match.Context);

if ((!IsResultTypeTrivial && IgnoreNonTrivialTypes))
return FixItHints;

if (IsResultTypeTrivial &&
static_cast<std::uint64_t>(
Match.Context->getTypeSizeInChars(ResultType).getQuantity()) >
IgnoreTrivialTypesOfSizeAbove)
return FixItHints;

for (const Expr *Arg : Result.Args) {
const auto *InnerCall = dyn_cast<CallExpr>(Arg->IgnoreParenImpCasts());

// If the argument is not a nested call
if (!InnerCall) {
// check if typecast is required
const QualType ArgType = Arg->IgnoreParenImpCasts()
->getType()
.getCanonicalType()
.getUnqualifiedType();

if (ArgType == ResultType)
continue;

const StringRef ArgText = Lexer::getSourceText(
CharSourceRange::getTokenRange(Arg->getSourceRange()), SourceMngr,
LanguageOpts);

const auto Replacement = Twine("static_cast<")
.concat(ResultType.getAsString(LanguageOpts))
.concat(">(")
.concat(ArgText)
.concat(")")
.str();

FixItHints.push_back(
FixItHint::CreateReplacement(Arg->getSourceRange(), Replacement));
continue;
}

const FindArgsResult InnerResult = findArgs(InnerCall);

// if the nested call doesn't have arguments skip it
if (!InnerResult.First || !InnerResult.Last)
continue;

// if the nested call is not the same as the top call
if (InnerCall->getDirectCallee()->getQualifiedNameAsString() !=
TopCall->getDirectCallee()->getQualifiedNameAsString())
continue;

// if the nested call doesn't have the same compare function
if ((Result.Compare || InnerResult.Compare) &&
!utils::areStatementsIdentical(Result.Compare, InnerResult.Compare,
*Match.Context))
continue;

// remove the function call
FixItHints.push_back(
FixItHint::CreateRemoval(InnerCall->getCallee()->getSourceRange()));

// remove the parentheses
const auto LParen = utils::lexer::findNextTokenSkippingComments(
InnerCall->getCallee()->getEndLoc(), SourceMngr, LanguageOpts);
if (LParen.has_value() && LParen->is(tok::l_paren))
FixItHints.push_back(
FixItHint::CreateRemoval(SourceRange(LParen->getLocation())));
FixItHints.push_back(
FixItHint::CreateRemoval(SourceRange(InnerCall->getRParenLoc())));

// if the inner call has an initializer list arg
if (InnerResult.First == InnerResult.Last) {
// remove the initializer list braces
FixItHints.push_back(FixItHint::CreateRemoval(
CharSourceRange::getTokenRange(InnerResult.First->getBeginLoc())));
FixItHints.push_back(FixItHint::CreateRemoval(
CharSourceRange::getTokenRange(InnerResult.First->getEndLoc())));
}

const SmallVector<FixItHint> InnerReplacements = generateReplacements(
Match, InnerCall, InnerResult, IgnoreNonTrivialTypes,
IgnoreTrivialTypesOfSizeAbove);

FixItHints.append(InnerReplacements);

if (InnerResult.Compare) {
// find the comma after the value arguments
const auto Comma = utils::lexer::findNextTokenSkippingComments(
InnerResult.Last->getEndLoc(), SourceMngr, LanguageOpts);

// remove the comma and the comparison
if (Comma.has_value() && Comma->is(tok::comma))
FixItHints.push_back(
FixItHint::CreateRemoval(SourceRange(Comma->getLocation())));

FixItHints.push_back(
FixItHint::CreateRemoval(InnerResult.Compare->getSourceRange()));
}
}

return FixItHints;
}

MinMaxUseInitializerListCheck::MinMaxUseInitializerListCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IgnoreNonTrivialTypes(Options.get("IgnoreNonTrivialTypes", true)),
IgnoreTrivialTypesOfSizeAbove(
Options.get("IgnoreTrivialTypesOfSizeAbove", 32L)),
Inserter(Options.getLocalOrGlobal("IncludeStyle",
utils::IncludeSorter::IS_LLVM),
areDiagsSelfContained()) {}

void MinMaxUseInitializerListCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IgnoreNonTrivialTypes", IgnoreNonTrivialTypes);
Options.store(Opts, "IgnoreTrivialTypesOfSizeAbove",
IgnoreTrivialTypesOfSizeAbove);
Options.store(Opts, "IncludeStyle", Inserter.getStyle());
}

void MinMaxUseInitializerListCheck::registerMatchers(MatchFinder *Finder) {
auto CreateMatcher = [](const StringRef FunctionName) {
auto FuncDecl = functionDecl(hasName(FunctionName));
auto Expression = callExpr(callee(FuncDecl));

return callExpr(callee(FuncDecl),
anyOf(hasArgument(0, Expression),
hasArgument(1, Expression),
hasArgument(0, cxxStdInitializerListExpr())),
unless(hasParent(Expression)))
.bind("topCall");
};

Finder->addMatcher(CreateMatcher("::std::max"), this);
Finder->addMatcher(CreateMatcher("::std::min"), this);
}

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

void MinMaxUseInitializerListCheck::check(
const MatchFinder::MatchResult &Match) {

const auto *TopCall = Match.Nodes.getNodeAs<CallExpr>("topCall");

const FindArgsResult Result = findArgs(TopCall);
const SmallVector<FixItHint> Replacements =
generateReplacements(Match, TopCall, Result, IgnoreNonTrivialTypes,
IgnoreTrivialTypesOfSizeAbove);

if (Replacements.empty())
return;

const DiagnosticBuilder Diagnostic =
diag(TopCall->getBeginLoc(),
"do not use nested 'std::%0' calls, use an initializer list instead")
<< TopCall->getDirectCallee()->getName()
<< Inserter.createIncludeInsertion(
Match.SourceManager->getFileID(TopCall->getBeginLoc()),
"<algorithm>");

// if the top call doesn't have an initializer list argument
if (Result.First != Result.Last) {
// add { and } insertions
Diagnostic << FixItHint::CreateInsertion(Result.First->getBeginLoc(), "{");

Diagnostic << FixItHint::CreateInsertion(
Lexer::getLocForEndOfToken(Result.Last->getEndLoc(), 0,
*Match.SourceManager,
Match.Context->getLangOpts()),
"}");
}

Diagnostic << Replacements;
}

} // namespace clang::tidy::modernize
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===--- MinMaxUseInitializerListCheck.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_MINMAXUSEINITIALIZERLISTCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MINMAXUSEINITIALIZERLISTCHECK_H

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

namespace clang::tidy::modernize {

/// Replaces nested ``std::min`` and ``std::max`` calls with an initializer list
/// where applicable.
///
/// For example:
///
/// \code
/// int a = std::max(std::max(i, j), k);
/// \endcode
///
/// This code is transformed to:
///
/// \code
/// int a = std::max({i, j, k});
/// \endcode
class MinMaxUseInitializerListCheck : public ClangTidyCheck {
public:
MinMaxUseInitializerListCheck(StringRef Name, ClangTidyContext *Context);

void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
Preprocessor *ModuleExpanderPP) override;
void check(const ast_matchers::MatchFinder::MatchResult &Match) override;

bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus11;
}
std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}

private:
bool IgnoreNonTrivialTypes;
std::uint64_t IgnoreTrivialTypesOfSizeAbove;
utils::IncludeInserter Inserter;
};

} // namespace clang::tidy::modernize

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MINMAXUSEINITIALIZERLISTCHECK_H
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "MacroToEnumCheck.h"
#include "MakeSharedCheck.h"
#include "MakeUniqueCheck.h"
#include "MinMaxUseInitializerListCheck.h"
#include "PassByValueCheck.h"
#include "RawStringLiteralCheck.h"
#include "RedundantVoidArgCheck.h"
Expand Down Expand Up @@ -68,6 +69,8 @@ class ModernizeModule : public ClangTidyModule {
CheckFactories.registerCheck<MacroToEnumCheck>("modernize-macro-to-enum");
CheckFactories.registerCheck<MakeSharedCheck>("modernize-make-shared");
CheckFactories.registerCheck<MakeUniqueCheck>("modernize-make-unique");
CheckFactories.registerCheck<MinMaxUseInitializerListCheck>(
"modernize-min-max-use-initializer-list");
CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
CheckFactories.registerCheck<UseDesignatedInitializersCheck>(
"modernize-use-designated-initializers");
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class UseNullptrCheck : public ClangTidyCheck {
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
// FIXME this should be CPlusPlus11 but that causes test cases to
// erroneously fail.
return LangOpts.CPlusPlus;
return LangOpts.CPlusPlus || LangOpts.C23;
}
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ void AvoidReturnWithVoidValueCheck::check(
<< BraceInsertionHints.closingBraceFixIt();
}
Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc());
if (!Result.Nodes.getNodeAs<FunctionDecl>("function_parent") ||
SurroundingBlock->body_back() != VoidReturn)
const auto *FunctionParent =
Result.Nodes.getNodeAs<FunctionDecl>("function_parent");
if (!FunctionParent ||
(SurroundingBlock && SurroundingBlock->body_back() != VoidReturn))
// If this is not the last statement in a function body, we add a `return`.
Diag << FixItHint::CreateInsertion(SemicolonPos.getLocWithOffset(1),
" return;", true);
}
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/readability/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ add_clang_library(clangTidyReadabilityModule
IsolateDeclarationCheck.cpp
MagicNumbersCheck.cpp
MakeMemberFunctionConstCheck.cpp
MathMissingParenthesesCheck.cpp
MisleadingIndentationCheck.cpp
MisplacedArrayIndexCheck.cpp
NamedParameterCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//===--- MathMissingParenthesesCheck.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 "MathMissingParenthesesCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"

using namespace clang::ast_matchers;

namespace clang::tidy::readability {

void MathMissingParenthesesCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(binaryOperator(unless(hasParent(binaryOperator())),
unless(isAssignmentOperator()),
unless(isComparisonOperator()),
unless(hasAnyOperatorName("&&", "||")),
hasDescendant(binaryOperator()))
.bind("binOp"),
this);
}

static int getPrecedence(const BinaryOperator *BinOp) {
if (!BinOp)
return 0;
switch (BinOp->getOpcode()) {
case BO_Mul:
case BO_Div:
case BO_Rem:
return 5;
case BO_Add:
case BO_Sub:
return 4;
case BO_And:
return 3;
case BO_Xor:
return 2;
case BO_Or:
return 1;
default:
return 0;
}
}
static void addParantheses(const BinaryOperator *BinOp,
const BinaryOperator *ParentBinOp,
ClangTidyCheck *Check,
const clang::SourceManager &SM,
const clang::LangOptions &LangOpts) {
if (!BinOp)
return;

int Precedence1 = getPrecedence(BinOp);
int Precedence2 = getPrecedence(ParentBinOp);

if (ParentBinOp != nullptr && Precedence1 != Precedence2) {
const clang::SourceLocation StartLoc = BinOp->getBeginLoc();
const clang::SourceLocation EndLoc =
clang::Lexer::getLocForEndOfToken(BinOp->getEndLoc(), 0, SM, LangOpts);

auto Diag =
Check->diag(StartLoc,
"'%0' has higher precedence than '%1'; add parentheses to "
"explicitly specify the order of operations")
<< (Precedence1 > Precedence2 ? BinOp->getOpcodeStr()
: ParentBinOp->getOpcodeStr())
<< (Precedence1 > Precedence2 ? ParentBinOp->getOpcodeStr()
: BinOp->getOpcodeStr())
<< SourceRange(StartLoc, EndLoc);

if (EndLoc.isValid()) {
Diag << FixItHint::CreateInsertion(StartLoc, "(")
<< FixItHint::CreateInsertion(EndLoc, ")");
}
}

addParantheses(dyn_cast<BinaryOperator>(BinOp->getLHS()->IgnoreImpCasts()),
BinOp, Check, SM, LangOpts);
addParantheses(dyn_cast<BinaryOperator>(BinOp->getRHS()->IgnoreImpCasts()),
BinOp, Check, SM, LangOpts);
}

void MathMissingParenthesesCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binOp");
std::vector<
std::pair<clang::SourceRange, std::pair<const clang::BinaryOperator *,
const clang::BinaryOperator *>>>
Insertions;
const SourceManager &SM = *Result.SourceManager;
const clang::LangOptions &LO = Result.Context->getLangOpts();
addParantheses(BinOp, nullptr, this, SM, LO);
}

} // namespace clang::tidy::readability
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===--- MathMissingParenthesesCheck.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_READABILITY_MATHMISSINGPARENTHESESCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MATHMISSINGPARENTHESESCHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::readability {

/// Check for mising parantheses in mathematical expressions that involve
/// operators of different priorities.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/readability/math-missing-parentheses.html
class MathMissingParenthesesCheck : public ClangTidyCheck {
public:
MathMissingParenthesesCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
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;
}
};

} // namespace clang::tidy::readability

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MATHMISSINGPARENTHESESCHECK_H
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "IsolateDeclarationCheck.h"
#include "MagicNumbersCheck.h"
#include "MakeMemberFunctionConstCheck.h"
#include "MathMissingParenthesesCheck.h"
#include "MisleadingIndentationCheck.h"
#include "MisplacedArrayIndexCheck.h"
#include "NamedParameterCheck.h"
Expand Down Expand Up @@ -105,6 +106,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-identifier-naming");
CheckFactories.registerCheck<ImplicitBoolConversionCheck>(
"readability-implicit-bool-conversion");
CheckFactories.registerCheck<MathMissingParenthesesCheck>(
"readability-math-missing-parentheses");
CheckFactories.registerCheck<RedundantInlineSpecifierCheck>(
"readability-redundant-inline-specifier");
CheckFactories.registerCheck<InconsistentDeclarationParameterNameCheck>(
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/CodeCompletionStrings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ void getSignature(const CodeCompletionString &CCS, std::string *Signature,
if (!IncludeFunctionArguments &&
ResultKind == CodeCompletionResult::RK_Declaration)
TruncateSnippetAt.emplace(Snippet->size());
LLVM_FALLTHROUGH;
[[fallthrough]];
case CodeCompletionString::CK_RightParen:
case CodeCompletionString::CK_LeftBracket:
case CodeCompletionString::CK_RightBracket:
Expand Down
8 changes: 4 additions & 4 deletions clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
EXPECT_DECLS("MemberExpr", "void foo()");

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

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

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

TEST_F(TargetDeclTest, DependentTypes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ sizeof...($TemplateParameter[[Elements]]);
struct $Class_def[[Foo]] {
int $Field_decl[[Waldo]];
void $Method_def[[bar]]() {
$Class[[Foo]]().$Field_dependentName[[Waldo]];
$Class[[Foo]]().$Field[[Waldo]];
}
template $Bracket[[<]]typename $TemplateParameter_def[[U]]$Bracket[[>]]
void $Method_def[[bar1]]() {
Expand Down
39 changes: 29 additions & 10 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,15 @@ Improvements to clang-tidy
- Improved :program:`run-clang-tidy.py` script. Added argument `-source-filter`
to filter source files from the compilation database, via a RegEx. In a
similar fashion to what `-header-filter` does for header files.

- Improved :program:`check_clang_tidy.py` script. Added argument `-export-fixes`
to aid in clang-tidy and test development.

- Fixed bug where big values for unsigned check options overflowed into negative values
when being printed with ``--dump-config``.
when being printed with `--dump-config`.

- Fixed ``--verify-config`` option not properly parsing checks when using the
literal operator in the ``.clang-tidy`` config.
- Fixed `--verify-config` option not properly parsing checks when using the
literal operator in the `.clang-tidy` config.

New checks
^^^^^^^^^^
Expand All @@ -131,6 +133,12 @@ New checks
to reading out-of-bounds data due to inadequate or incorrect string null
termination.

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

Replaces nested ``std::min`` and ``std::max`` calls with an initializer list
where applicable.

- New :doc:`modernize-use-designated-initializers
<clang-tidy/checks/modernize/use-designated-initializers>` check.

Expand All @@ -143,6 +151,12 @@ New checks
Enforces consistent style for enumerators' initialization, covering three
styles: none, first only, or all initialized explicitly.

- New :doc:`readability-math-missing-parentheses
<clang-tidy/checks/readability/math-missing-parentheses>` check.

Check for missing parentheses in mathematical expressions that involve
operators of different priorities.

- New :doc:`readability-use-std-min-max
<clang-tidy/checks/readability/use-std-min-max>` check.

Expand Down Expand Up @@ -224,7 +238,7 @@ Changes in existing checks

- Improved :doc:`google-explicit-constructor
<clang-tidy/checks/google/explicit-constructor>` check to better handle
``C++-20`` `explicit(bool)`.
C++20 `explicit(bool)`.

- Improved :doc:`google-global-names-in-headers
<clang-tidy/checks/google/global-names-in-headers>` check by replacing the local
Expand All @@ -237,13 +251,18 @@ Changes in existing checks
check by ignoring other functions with same prefixes as the target specific
functions.

- Improved :doc:`linuxkernel-must-check-errs
<clang-tidy/checks/linuxkernel/must-check-errs>` check documentation to
consistently use the check's proper name.

- Improved :doc:`llvm-header-guard
<clang-tidy/checks/llvm/header-guard>` check by replacing the local
option `HeaderFileExtensions` by the global option of the same name.

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

- Improved :doc:`misc-definitions-in-headers
<clang-tidy/checks/misc/definitions-in-headers>` check by replacing the local
Expand All @@ -269,6 +288,10 @@ Changes in existing checks
don't remove parentheses used in ``sizeof`` calls when they have array index
accesses as arguments.

- Improved :doc:`modernize-use-nullptr
<clang-tidy/checks/modernize/use-nullptr>` check to include support for C23,
which also has introduced the ``nullptr`` keyword.

- Improved :doc:`modernize-use-override
<clang-tidy/checks/modernize/use-override>` check to also remove any trailing
whitespace when deleting the ``virtual`` keyword.
Expand Down Expand Up @@ -324,13 +347,9 @@ Miscellaneous
^^^^^^^^^^^^^

- Fixed incorrect formatting in :program:`clang-apply-replacements` when no
``--format`` option is specified. Now :program:`clang-apply-replacements`
`--format` option is specified. Now :program:`clang-apply-replacements`
applies formatting only with the option.

- Fixed the :doc:`linuxkernel-must-check-errs
<clang-tidy/checks/linuxkernel/must-check-errs>` documentation to consistently
use the check's proper name.

Improvements to include-fixer
-----------------------------

Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/docs/clang-tidy/checks/cert/env33-c.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ but does not actually attempt to execute a command.

This check corresponds to the CERT C Coding Standard rule
`ENV33-C. Do not call system()
<https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=2130132>`_.
<https://www.securecoding.cert.org/confluence/display/c/ENV33-C.+Do+not+call+system()>`_.
2 changes: 2 additions & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ Clang-Tidy Checks
:doc:`modernize-macro-to-enum <modernize/macro-to-enum>`, "Yes"
:doc:`modernize-make-shared <modernize/make-shared>`, "Yes"
:doc:`modernize-make-unique <modernize/make-unique>`, "Yes"
:doc:`modernize-min-max-use-initializer-list <modernize/min-max-use-initializer-list>`, "Yes"
:doc:`modernize-pass-by-value <modernize/pass-by-value>`, "Yes"
:doc:`modernize-raw-string-literal <modernize/raw-string-literal>`, "Yes"
:doc:`modernize-redundant-void-arg <modernize/redundant-void-arg>`, "Yes"
Expand Down Expand Up @@ -363,6 +364,7 @@ Clang-Tidy Checks
:doc:`readability-isolate-declaration <readability/isolate-declaration>`, "Yes"
:doc:`readability-magic-numbers <readability/magic-numbers>`,
:doc:`readability-make-member-function-const <readability/make-member-function-const>`, "Yes"
:doc:`readability-math-missing-parentheses <readability/math-missing-parentheses>`, "Yes"
:doc:`readability-misleading-indentation <readability/misleading-indentation>`,
:doc:`readability-misplaced-array-index <readability/misplaced-array-index>`, "Yes"
:doc:`readability-named-parameter <readability/named-parameter>`, "Yes"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
.. title:: clang-tidy - modernize-min-max-use-initializer-list

modernize-min-max-use-initializer-list
======================================

Replaces nested ``std::min`` and ``std::max`` calls with an initializer list
where applicable.

For instance, consider the following code:

.. code-block:: cpp
int a = std::max(std::max(i, j), k);
The check will transform the above code to:

.. code-block:: cpp
int a = std::max({i, j, k});
Performance Considerations
==========================

While this check simplifies the code and makes it more readable, it may cause
performance degradation for non-trivial types due to the need to copy objects
into the initializer list.

To avoid this, it is recommended to use `std::ref` or `std::cref` for
non-trivial types:

.. code-block:: cpp
std::string b = std::max({std::ref(i), std::ref(j), std::ref(k)});
Options
=======

.. option:: IncludeStyle

A string specifying which include-style is used, `llvm` or `google`. Default
is `llvm`.

.. option:: IgnoreNonTrivialTypes

A boolean specifying whether to ignore non-trivial types. Default is `true`.

.. option:: IgnoreTrivialTypesOfSizeAbove

An integer specifying the size (in bytes) above which trivial types are
ignored. Default is `32`.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ modernize-use-nullptr
=====================

The check converts the usage of null pointer constants (e.g. ``NULL``, ``0``)
to use the new C++11 ``nullptr`` keyword.
to use the new C++11 and C23 ``nullptr`` keyword.

Example
-------
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.. title:: clang-tidy - readability-math-missing-parentheses

readability-math-missing-parentheses
====================================

Check for missing parentheses in mathematical expressions that involve operators
of different priorities.

Parentheses in mathematical expressions clarify the order
of operations, especially with different-priority operators. Lengthy or multiline
expressions can obscure this order, leading to coding errors. IDEs can aid clarity
by highlighting parentheses. Explicitly using parentheses also clarifies what the
developer had in mind when writing the expression. Ensuring their presence reduces
ambiguity and errors, promoting clearer and more maintainable code.

Before:

.. code-block:: c++

int x = 1 + 2 * 3 - 4 / 5;


After:

.. code-block:: c++

int x = 1 + (2 * 3) - (4 / 5);
45 changes: 21 additions & 24 deletions clang-tools-extra/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,33 +67,30 @@ foreach(dep ${LLVM_UTILS_DEPS})
endif()
endforeach()

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

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

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

add_lit_testsuite(check-clang-extra "Running clang-tools-extra/test"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ struct HeapArray { // Ok, since destruc

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
// RUN: %check_clang_tidy %s modernize-min-max-use-initializer-list %t

// CHECK-FIXES: #include <algorithm>
namespace utils {
template <typename T>
T max(T a, T b) {
return (a < b) ? b : a;
}
} // namespace utils

namespace std {
template< class T >
struct initializer_list {
initializer_list()=default;
initializer_list(T*,int){}
const T* begin() const {return nullptr;}
const T* end() const {return nullptr;}
};

template<class ForwardIt>
ForwardIt min_element(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;

ForwardIt smallest = first;

while (++first != last)
if (*first < *smallest)
smallest = first;

return smallest;
}

template<class ForwardIt, class Compare>
ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp)
{
if (first == last)
return last;

ForwardIt smallest = first;

while (++first != last)
if (comp(*first, *smallest))
smallest = first;

return smallest;
}

template<class ForwardIt>
ForwardIt max_element(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;

ForwardIt largest = first;

while (++first != last)
if (*largest < *first)
largest = first;

return largest;
}

template<class ForwardIt, class Compare>
ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp)
{
if (first == last)
return last;

ForwardIt largest = first;

while(++first != last)
if (comp(*largest, *first))
largest = first;

return largest;
}

template< class T >
const T& max( const T& a, const T& b ) {
return (a < b) ? b : a;
};

template< class T >
T max(std::initializer_list<T> ilist)
{
return *std::max_element(ilist.begin(), ilist.end());
}

template< class T, class Compare >
const T& max( const T& a, const T& b, Compare comp ) {
return (comp(a, b)) ? b : a;
};

template< class T, class Compare >
T max(std::initializer_list<T> ilist, Compare comp) {
return *std::max_element(ilist.begin(), ilist.end(), comp);
};

template< class T >
const T& min( const T& a, const T& b ) {
return (b < a) ? b : a;
};

template< class T >
T min(std::initializer_list<T> ilist)
{
return *std::min_element(ilist.begin(), ilist.end());
}


template< class T, class Compare >
const T& min( const T& a, const T& b, Compare comp ) {
return (comp(b, a)) ? b : a;
};

template< class T, class Compare >
T min(std::initializer_list<T> ilist, Compare comp) {
return *std::min_element(ilist.begin(), ilist.end(), comp);
};

} // namespace std

using namespace std;

namespace {
bool fless_than(int a, int b) {
return a < b;
}

bool fgreater_than(int a, int b) {
return a > b;
}
auto less_than = [](int a, int b) { return a < b; };
auto greater_than = [](int a, int b) { return a > b; };

int max1 = std::max(1, std::max(2, 3));
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max1 = std::max({1, 2, 3});

int min1 = std::min(1, std::min(2, 3));
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int min1 = std::min({1, 2, 3});

int max2 = std::max(1, std::max(2, std::max(3, 4)));
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max2 = std::max({1, 2, 3, 4});

int max2b = std::max(std::max(std::max(1, 2), std::max(3, 4)), std::max(std::max(5, 6), std::max(7, 8)));
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max2b = std::max({1, 2, 3, 4, 5, 6, 7, 8});

int max2c = std::max(std::max(1, std::max(2, 3)), 4);
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max2c = std::max({1, 2, 3, 4});

int max2d = std::max(std::max({1, 2, 3}), 4);
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max2d = std::max({1, 2, 3, 4});


int max2e = std::max(1, max(2, max(3, 4)));
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max2e = std::max({1, 2, 3, 4});

int min2 = std::min(1, std::min(2, std::min(3, 4)));
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int min2 = std::min({1, 2, 3, 4});

int max3 = std::max(std::max(4, 5), std::min(2, std::min(3, 1)));
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max3 = std::max({4, 5, std::min({2, 3, 1})});

int min3 = std::min(std::min(4, 5), std::max(2, std::max(3, 1)));
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int min3 = std::min({4, 5, std::max({2, 3, 1})});

int max4 = std::max(1, std::max(2, 3, greater_than), less_than);
// CHECK-FIXES: int max4 = std::max(1, std::max(2, 3, greater_than), less_than);

int min4 = std::min(1, std::min(2, 3, greater_than), less_than);
// CHECK-FIXES: int min4 = std::min(1, std::min(2, 3, greater_than), less_than);

int max5 = std::max(1, std::max(2, 3), less_than);
// CHECK-FIXES: int max5 = std::max(1, std::max(2, 3), less_than);

int min5 = std::min(1, std::min(2, 3), less_than);
// CHECK-FIXES: int min5 = std::min(1, std::min(2, 3), less_than);

int max6 = std::max(1, std::max(2, 3, greater_than), greater_than);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max6 = std::max({1, 2, 3 }, greater_than);

int min6 = std::min(1, std::min(2, 3, greater_than), greater_than);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int min6 = std::min({1, 2, 3 }, greater_than);

int max7 = std::max(1, std::max(2, 3, fless_than), fgreater_than);
// CHECK-FIXES: int max7 = std::max(1, std::max(2, 3, fless_than), fgreater_than);

int min7 = std::min(1, std::min(2, 3, fless_than), fgreater_than);
// CHECK-FIXES: int min7 = std::min(1, std::min(2, 3, fless_than), fgreater_than);

int max8 = std::max(1, std::max(2, 3, fless_than), less_than);
// CHECK-FIXES: int max8 = std::max(1, std::max(2, 3, fless_than), less_than)

int min8 = std::min(1, std::min(2, 3, fless_than), less_than);
// CHECK-FIXES: int min8 = std::min(1, std::min(2, 3, fless_than), less_than);

int max9 = std::max(1, std::max(2, 3, fless_than), fless_than);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max9 = std::max({1, 2, 3 }, fless_than);

int min9 = std::min(1, std::min(2, 3, fless_than), fless_than);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int min9 = std::min({1, 2, 3 }, fless_than);

int min10 = std::min(std::min(4, 5), std::max(2, utils::max(3, 1)));
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int min10 = std::min({4, 5, std::max(2, utils::max(3, 1))});

int max10 = std::max({std::max(1, 2), std::max({5, 6, 1}), 2, std::min({1, 2, 4})});
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int max10 = std::max({1, 2, 5, 6, 1, 2, std::min({1, 2, 4})});

int typecastTest = std::max(std::max<int>(0U, 0.0f), 0);
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int typecastTest = std::max({static_cast<int>(0U), static_cast<int>(0.0f), 0});

int typecastTest1 = std::max(std::max<long>(0U, 0.0f), 0L);
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int typecastTest1 = std::max({static_cast<long>(0U), static_cast<long>(0.0f), 0L});

int typecastTest2 = std::max(std::max<int>(10U, 20.0f), 30);
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int typecastTest2 = std::max({static_cast<int>(10U), static_cast<int>(20.0f), 30});

int typecastTest3 = std::max(std::max<int>(0U, std::max<int>(0.0f, 1.0f)), 0);
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int typecastTest3 = std::max({static_cast<int>(0U), static_cast<int>(0.0f), static_cast<int>(1.0f), 0});

#define max3f(a, b, c) std::max(a, std::max(b, c))
// CHECK-FIXES: #define max3f(a, b, c) std::max(a, std::max(b, c))

#define value 4545
int macroVarMax = std::max(value, std::max(1, 2));
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int macroVarMax = std::max({value, 1, 2});

#define value2 45U
int macroVarMax2 = std::max(1, std::max<int>(value2, 2.0f));
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list]
// CHECK-FIXES: int macroVarMax2 = std::max({1, static_cast<int>(value2), static_cast<int>(2.0f)});

// True-negative tests
int maxTN1 = std::max(1, 2);
// CHECK-FIXES: int maxTN1 = std::max(1, 2);

int maxTN2 = std::max({1, 2, 3});
// CHECK-FIXES: int maxTN2 = std::max({1, 2, 3});

int maxTN3 = std::max({1, 2, 3}, less_than);
// CHECK-FIXES: int maxTN3 = std::max({1, 2, 3}, less_than);

// non-trivial types
struct A {
int a;
A(int a) : a(a) {}
bool operator<(const A &rhs) const { return a < rhs.a; }
};

A maxNT1 = std::max(A(1), A(2));
// CHECK-FIXES: A maxNT1 = std::max(A(1), A(2));

A maxNT2 = std::max(A(1), std::max(A(2), A(3)));
// CHECK-FIXES: A maxNT2 = std::max(A(1), std::max(A(2), A(3)));

A maxNT3 = std::max(A(1), std::max(A(2), A(3)), [](const A &lhs, const A &rhs) { return lhs.a < rhs.a; });
// CHECK-FIXES: A maxNT3 = std::max(A(1), std::max(A(2), A(3)), [](const A &lhs, const A &rhs) { return lhs.a < rhs.a; });

// Trivial type with size greater than 32
struct B {
// 9*4 = 36 bytes > 32 bytes
int a[9];

bool operator<(const B& rhs) const {
return a[0] < rhs.a[0];
}
};

B maxTT1 = std::max(B(), B());
// CHECK-FIXES: B maxTT1 = std::max(B(), B());

B maxTT2 = std::max(B(), std::max(B(), B()));
// CHECK-FIXES: B maxTT2 = std::max(B(), std::max(B(), B()));

B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; });
// CHECK-FIXES: B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; });


} // namespace

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

Template<int> T1;


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

DT1<int> Dt1;

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

DT2<T> Dt2;

// Default arguments.
Expand Down
139 changes: 139 additions & 0 deletions clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// RUN: %check_clang_tidy %s modernize-use-nullptr %t -- -- -std=c23

#define NULL 0

void test_assignment() {
int *p1 = 0;
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr [modernize-use-nullptr]
// CHECK-FIXES: int *p1 = nullptr;
p1 = 0;
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr
// CHECK-FIXES: p1 = nullptr;

int *p2 = NULL;
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
// CHECK-FIXES: int *p2 = nullptr;

p2 = p1;
// CHECK-FIXES: p2 = p1;

const int null = 0;
int *p3 = &null;

p3 = NULL;
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr
// CHECK-FIXES: p3 = nullptr;

int *p4 = p3;

int i1 = 0;

int i2 = NULL;

int i3 = null;

int *p5, *p6, *p7;
p5 = p6 = p7 = NULL;
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr
// CHECK-FIXES: p5 = p6 = p7 = nullptr;
}

void test_function(int *p) {}

void test_function_no_ptr_param(int i) {}

void test_function_call() {
test_function(0);
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
// CHECK-FIXES: test_function(nullptr);

test_function(NULL);
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
// CHECK-FIXES: test_function(nullptr);

test_function_no_ptr_param(0);
}

char *test_function_return1() {
return 0;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
// CHECK-FIXES: return nullptr;
}

void *test_function_return2() {
return NULL;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
// CHECK-FIXES: return nullptr;
}

int test_function_return4() {
return 0;
}

int test_function_return5() {
return NULL;
}

int *test_function_return_cast1() {
return(int)0;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
// CHECK-FIXES: return nullptr;
}

int *test_function_return_cast2() {
#define RET return
RET(int)0;
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use nullptr
// CHECK-FIXES: RET nullptr;
#undef RET
}

// Test parentheses expressions resulting in a nullptr.
int *test_parentheses_expression1() {
return(0);
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
// CHECK-FIXES: return(nullptr);
}

int *test_parentheses_expression2() {
return((int)(0.0f));
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
// CHECK-FIXES: return(nullptr);
}

int *test_nested_parentheses_expression() {
return((((0))));
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
// CHECK-FIXES: return((((nullptr))));
}

void test_const_pointers() {
const int *const_p1 = 0;
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
// CHECK-FIXES: const int *const_p1 = nullptr;
const int *const_p2 = NULL;
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
// CHECK-FIXES: const int *const_p2 = nullptr;
const int *const_p3 = (int)0;
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
// CHECK-FIXES: const int *const_p3 = nullptr;
const int *const_p4 = (int)0.0f;
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
// CHECK-FIXES: const int *const_p4 = nullptr;
}

void test_nested_implicit_cast_expr() {
int func0(void*, void*);
int func1(int, void*, void*);

(double)func1(0, 0, 0);
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use nullptr
// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use nullptr
// CHECK-FIXES: (double)func1(0, nullptr, nullptr);
(double)func1(func0(0, 0), 0, 0);
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use nullptr
// CHECK-MESSAGES: :[[@LINE-2]]:26: warning: use nullptr
// CHECK-MESSAGES: :[[@LINE-3]]:30: warning: use nullptr
// CHECK-MESSAGES: :[[@LINE-4]]:33: warning: use nullptr
// CHECK-FIXES: (double)func1(func0(nullptr, nullptr), nullptr, nullptr);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: clang-tidy %s -checks=-*,modernize-use-nullptr -- | count 0
// RUN: clang-tidy %s -checks=-*,modernize-use-nullptr -- -std=c17 | count 0

// Note: this test expects no diagnostics, but FileCheck cannot handle that,
// hence the use of | count 0.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// RUN: %check_clang_tidy %s readability-math-missing-parentheses %t

#define MACRO_AND &
#define MACRO_ADD +
#define MACRO_OR |
#define MACRO_MULTIPLY *
#define MACRO_XOR ^
#define MACRO_SUBTRACT -
#define MACRO_DIVIDE /

int foo(){
return 5;
}

int bar(){
return 4;
}

int sink(int);
#define FUN(ARG) (sink(ARG))
#define FUN2(ARG) sink((ARG))
#define FUN3(ARG) sink(ARG)
#define FUN4(ARG) sink(1 + ARG)
#define FUN5(ARG) sink(4 * ARG)

class fun{
public:
int A;
double B;
fun(){
A = 5;
B = 5.4;
}
};

void f(){
//CHECK-MESSAGES: :[[@LINE+2]]:17: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int a = 1 + (2 * 3);
int a = 1 + 2 * 3;

int a_negative = 1 + (2 * 3); // No warning

int b = 1 + 2 + 3; // No warning

int c = 1 * 2 * 3; // No warning

//CHECK-MESSAGES: :[[@LINE+3]]:17: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+2]]:25: warning: '/' has higher precedence than '-'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int d = 1 + (2 * 3) - (4 / 5);
int d = 1 + 2 * 3 - 4 / 5;

int d_negative = 1 + (2 * 3) - (4 / 5); // No warning

//CHECK-MESSAGES: :[[@LINE+4]]:13: warning: '&' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+3]]:17: warning: '+' has higher precedence than '&'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+2]]:25: warning: '*' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int e = (1 & (2 + 3)) | (4 * 5);
int e = 1 & 2 + 3 | 4 * 5;

int e_negative = (1 & (2 + 3)) | (4 * 5); // No warning

//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int f = (1 * -2) + 4;
int f = 1 * -2 + 4;

int f_negative = (1 * -2) + 4; // No warning

//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int g = (1 * 2 * 3) + 4 + 5;
int g = 1 * 2 * 3 + 4 + 5;

int g_negative = (1 * 2 * 3) + 4 + 5; // No warning

//CHECK-MESSAGES: :[[@LINE+4]]:13: warning: '&' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+3]]:19: warning: '+' has higher precedence than '&'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+2]]:27: warning: '*' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int h = (120 & (2 + 3)) | (22 * 5);
int h = 120 & 2 + 3 | 22 * 5;

int h_negative = (120 & (2 + 3)) | (22 * 5); // No warning

int i = 1 & 2 & 3; // No warning

int j = 1 | 2 | 3; // No warning

int k = 1 ^ 2 ^ 3; // No warning

//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '+' has higher precedence than '^'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int l = (1 + 2) ^ 3;
int l = 1 + 2 ^ 3;

int l_negative = (1 + 2) ^ 3; // No warning

//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int m = (2 * foo()) + bar();
int m = 2 * foo() + bar();

int m_negative = (2 * foo()) + bar(); // No warning

//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int n = (1.05 * foo()) + double(bar());
int n = 1.05 * foo() + double(bar());

int n_negative = (1.05 * foo()) + double(bar()); // No warning

//CHECK-MESSAGES: :[[@LINE+3]]:17: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int o = 1 + (obj.A * 3) + obj.B;
fun obj;
int o = 1 + obj.A * 3 + obj.B;

int o_negative = 1 + (obj.A * 3) + obj.B; // No warning

//CHECK-MESSAGES: :[[@LINE+2]]:18: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int p = 1U + (2 * 3);
int p = 1U + 2 * 3;

int p_negative = 1U + (2 * 3); // No warning

//CHECK-MESSAGES: :[[@LINE+7]]:13: warning: '+' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+6]]:25: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+5]]:53: warning: '&' has higher precedence than '^'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+4]]:53: warning: '^' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+3]]:77: warning: '-' has higher precedence than '^'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-MESSAGES: :[[@LINE+2]]:94: warning: '/' has higher precedence than '-'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
//CHECK-FIXES: int q = (1 MACRO_ADD (2 MACRO_MULTIPLY 3)) MACRO_OR ((4 MACRO_AND 5) MACRO_XOR (6 MACRO_SUBTRACT (7 MACRO_DIVIDE 8)));
int q = 1 MACRO_ADD 2 MACRO_MULTIPLY 3 MACRO_OR 4 MACRO_AND 5 MACRO_XOR 6 MACRO_SUBTRACT 7 MACRO_DIVIDE 8; // No warning

//CHECK-MESSAGES: :[[@LINE+1]]:21: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int r = FUN(0 + 1 * 2);

//CHECK-MESSAGES: :[[@LINE+1]]:22: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int s = FUN2(0 + 1 * 2);

//CHECK-MESSAGES: :[[@LINE+1]]:22: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int t = FUN3(0 + 1 * 2);

//CHECK-MESSAGES: :[[@LINE+1]]:18: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int u = FUN4(1 * 2);

//CHECK-MESSAGES: :[[@LINE+1]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
int v = FUN5(0 + 1);
}
2 changes: 1 addition & 1 deletion clang-tools-extra/test/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ config.python_executable = "@Python3_EXECUTABLE@"
config.target_triple = "@LLVM_TARGET_TRIPLE@"
config.host_triple = "@LLVM_HOST_TRIPLE@"
config.clang_tidy_staticanalyzer = @CLANG_TIDY_ENABLE_STATIC_ANALYZER@
config.has_plugins = @CLANG_PLUGIN_SUPPORT@ & ~@LLVM_INSTALL_TOOLCHAIN_ONLY@
config.has_plugins = @CLANG_PLUGIN_SUPPORT@
# Support substitution of the tools and libs dirs with user parameters. This is
# used when we can't determine the tool dir at configuration time.
config.llvm_tools_dir = lit_config.substitute("@LLVM_TOOLS_DIR@")
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/test/pp-trace/pp-trace-pragma-general.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ void foo() {

// CHECK: ---
// CHECK-NEXT: - Callback: PragmaDirective
// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1"
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaDirective
// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1"
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaDirective
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:3:1"
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaDiagnosticPush
Expand Down
8 changes: 7 additions & 1 deletion clang-tools-extra/test/pp-trace/pp-trace-pragma-ms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@

// CHECK: ---
// CHECK-NEXT: - Callback: PragmaDirective
// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1"
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaDirective
// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1"
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaDirective
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:3:1"
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaComment
Expand Down Expand Up @@ -67,7 +73,7 @@
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaMessage
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:13:9"
// CHECK-NEXT: Namespace:
// CHECK-NEXT: Namespace:
// CHECK-NEXT: Kind: PMK_Message
// CHECK-NEXT: Str: message argument
// CHECK-NEXT: - Callback: PragmaDirective
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/test/pp-trace/pp-trace-pragma-opencl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@

// CHECK: ---
// CHECK-NEXT: - Callback: PragmaDirective
// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1"
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaDirective
// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1"
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaDirective
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:3:1"
// CHECK-NEXT: Introducer: PIK_HashPragma
// CHECK-NEXT: - Callback: PragmaOpenCLExtension
Expand Down
4 changes: 4 additions & 0 deletions clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ if(CLANG_ENABLE_LIBXML2)
endif()

if(CLANG_ENABLE_CIR)
if (CLANG_BUILT_STANDALONE)
message(FATAL_ERROR
"ClangIR is not yet supported in the standalone build.")
endif()
if (NOT "${LLVM_ENABLE_PROJECTS}" MATCHES "MLIR|mlir")
message(FATAL_ERROR
"Cannot build ClangIR without MLIR in LLVM_ENABLE_PROJECTS")
Expand Down
135 changes: 67 additions & 68 deletions clang/cmake/caches/Release.cmake
Original file line number Diff line number Diff line change
@@ -1,95 +1,94 @@
# Plain options configure the first build.
# BOOTSTRAP_* options configure the second build.
# BOOTSTRAP_BOOTSTRAP_* options configure the third build.
# PGO Builds have 3 stages (stage1, stage2-instrumented, stage2)
# non-PGO Builds have 2 stages (stage1, stage2)

# General Options

function (set_final_stage_var name value type)
if (LLVM_RELEASE_ENABLE_PGO)
set(BOOTSTRAP_BOOTSTRAP_${name} ${value} CACHE ${type} "")
else()
set(BOOTSTRAP_${name} ${value} CACHE ${type} "")
endif()
endfunction()

function (set_instrument_and_final_stage_var name value type)
# This sets the varaible for the final stage in non-PGO builds and in
# the stage2-instrumented stage for PGO builds.
set(BOOTSTRAP_${name} ${value} CACHE ${type} "")
if (LLVM_RELEASE_ENABLE_PGO)
# Set the variable in the final stage for PGO builds.
set(BOOTSTRAP_BOOTSTRAP_${name} ${value} CACHE ${type} "")
endif()
endfunction()

# General Options:
# If you want to override any of the LLVM_RELEASE_* variables you can set them
# on the command line via -D, but you need to do this before you pass this
# cache file to CMake via -C. e.g.
#
# cmake -D LLVM_RELEASE_ENABLE_PGO=ON -C Release.cmake
set(LLVM_RELEASE_ENABLE_LTO THIN CACHE STRING "")
set(LLVM_RELEASE_ENABLE_PGO OFF CACHE BOOL "")

set(LLVM_RELEASE_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "")
set(LLVM_RELEASE_ENABLE_PROJECTS "clang;lld;lldb;clang-tools-extra;bolt;polly;mlir;flang" CACHE STRING "")
# Note we don't need to add install here, since it is one of the pre-defined
# steps.
set(LLVM_RELEASE_FINAL_STAGE_TARGETS "clang;package;check-all;check-llvm;check-clang" CACHE STRING "")
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")

# Stage 1 Bootstrap Setup
# Stage 1 Options
set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "")
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")

set(STAGE1_PROJECTS "clang")
set(STAGE1_RUNTIMES "")

if (LLVM_RELEASE_ENABLE_PGO)
list(APPEND STAGE1_PROJECTS "lld")
list(APPEND STAGE1_RUNTIMES "compiler-rt")
set(CLANG_BOOTSTRAP_TARGETS
generate-profdata
stage2
stage2-package
stage2-clang
stage2-distribution
stage2-install
stage2-install-distribution
stage2-install-distribution-toolchain
stage2-check-all
stage2-check-llvm
stage2-check-clang
stage2-test-suite CACHE STRING "")
else()
set(CLANG_BOOTSTRAP_TARGETS
clang
check-all
check-llvm
check-clang
test-suite
stage3
stage3-clang
stage3-check-all
stage3-check-llvm
stage3-check-clang
stage3-install
stage3-test-suite CACHE STRING "")
endif()
stage2-check-clang CACHE STRING "")

# Stage 1 Options
set(STAGE1_PROJECTS "clang")
set(STAGE1_RUNTIMES "")
# Configuration for stage2-instrumented
set(BOOTSTRAP_CLANG_ENABLE_BOOTSTRAP ON CACHE STRING "")
# This enables the build targets for the final stage which is called stage2.
set(BOOTSTRAP_CLANG_BOOTSTRAP_TARGETS ${LLVM_RELEASE_FINAL_STAGE_TARGETS} CACHE STRING "")
set(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED IR CACHE STRING "")
set(BOOTSTRAP_LLVM_ENABLE_RUNTIMES "compiler-rt" CACHE STRING "")
set(BOOTSTRAP_LLVM_ENABLE_PROJECTS "clang;lld" CACHE STRING "")

if (LLVM_RELEASE_ENABLE_PGO)
list(APPEND STAGE1_PROJECTS "lld")
list(APPEND STAGE1_RUNTIMES "compiler-rt")
else()
if (LLVM_RELEASE_ENABLE_LTO)
list(APPEND STAGE1_PROJECTS "lld")
endif()
# Any targets added here will be given the target name stage2-${target}, so
# if you want to run them you can just use:
# ninja -C $BUILDDIR stage2-${target}
set(CLANG_BOOTSTRAP_TARGETS ${LLVM_RELEASE_FINAL_STAGE_TARGETS} CACHE STRING "")
endif()

# Stage 1 Common Config
set(LLVM_ENABLE_RUNTIMES ${STAGE1_RUNTIMES} CACHE STRING "")
set(LLVM_ENABLE_PROJECTS ${STAGE1_PROJECTS} CACHE STRING "")

set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "")

# Stage 2 Bootstrap Setup
set(BOOTSTRAP_CLANG_ENABLE_BOOTSTRAP ON CACHE STRING "")
set(BOOTSTRAP_CLANG_BOOTSTRAP_TARGETS
clang
package
check-all
check-llvm
check-clang CACHE STRING "")

# Stage 2 Options
set(STAGE2_PROJECTS "clang")
set(STAGE2_RUNTIMES "")

if (LLVM_RELEASE_ENABLE_LTO OR LLVM_RELEASE_ENABLE_PGO)
list(APPEND STAGE2_PROJECTS "lld")
endif()

if (LLVM_RELEASE_ENABLE_PGO)
set(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED IR CACHE STRING "")
list(APPEND STAGE2_RUNTIMES "compiler-rt")
set(BOOTSTRAP_LLVM_ENABLE_LTO ${LLVM_RELEASE_ENABLE_LTO})
if (LLVM_RELEASE_ENABLE_LTO)
set(BOOTSTRAP_LLVM_ENABLE_LLD ON CACHE BOOL "")
endif()
# stage2-instrumented and Final Stage Config:
# Options that need to be set in both the instrumented stage (if we are doing
# a pgo build) and the final stage.
set_instrument_and_final_stage_var(CMAKE_POSITION_INDEPENDENT_CODE "ON" STRING)
set_instrument_and_final_stage_var(LLVM_ENABLE_LTO "${LLVM_RELEASE_ENABLE_LTO}" STRING)
if (LLVM_RELEASE_ENABLE_LTO)
set_instrument_and_final_stage_var(LLVM_ENABLE_LLD "ON" BOOL)
endif()

set(BOOTSTRAP_LLVM_ENABLE_PROJECTS ${STAGE2_PROJECTS} CACHE STRING "")
set(BOOTSTRAP_LLVM_ENABLE_RUNTIMES ${STAGE2_RUNTIMES} CACHE STRING "")
if (NOT LLVM_RELEASE_ENABLE_PGO)
set(BOOTSTRAP_LLVM_TARGETS_TO_BUILD Native CACHE STRING "")
endif()
# Final Stage Config (stage2)
set_final_stage_var(LLVM_ENABLE_RUNTIMES "${LLVM_RELEASE_ENABLE_RUNTIMES}" STRING)
set_final_stage_var(LLVM_ENABLE_PROJECTS "${LLVM_RELEASE_ENABLE_PROJECTS}" STRING)

# Stage 3 Options
set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "")
set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_PROJECTS "clang;lld;lldb;clang-tools-extra;bolt;polly;mlir;flang" CACHE STRING "")
set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LTO ${LLVM_RELEASE_ENABLE_LTO} CACHE STRING "")
if (LLVM_RELEASE_ENABLE_LTO)
set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LLD ON CACHE BOOL "")
endif()
2 changes: 2 additions & 0 deletions clang/cmake/caches/VectorEngine.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_CRT OFF CACHE BOOL "")
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL "")
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "")
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_LIBFUZZER OFF CACHE BOOL "")
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_CTX_PROFILE OFF CACHE BOOL "")
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_PROFILE OFF CACHE BOOL "")
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_MEMPROF OFF CACHE BOOL "")
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_ORC OFF CACHE BOOL "")
Expand All @@ -52,6 +53,7 @@ set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL ""
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "")
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_LIBFUZZER OFF CACHE BOOL "")
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_PROFILE ON CACHE BOOL "")
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_CTX_PROFILE OFF CACHE BOOL "")
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_MEMPROF OFF CACHE BOOL "")
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_ORC OFF CACHE BOOL "")
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_GWP_ASAN OFF CACHE BOOL "")
Expand Down
33 changes: 30 additions & 3 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,8 @@ even-odd element pair with indices ``i * 2`` and ``i * 2 + 1`` with
power of 2, the vector is widened with neutral elements for the reduction
at the end to the next power of 2.

These reductions support both fixed-sized and scalable vector types.

Example:

.. code-block:: c++
Expand Down Expand Up @@ -1493,6 +1495,7 @@ Conditional ``explicit`` __cpp_conditional_explicit C+
``if consteval`` __cpp_if_consteval C++23 C++20
``static operator()`` __cpp_static_call_operator C++23 C++03
Attributes on Lambda-Expressions C++23 C++11
Attributes on Structured Bindings __cpp_structured_bindings C++26 C++03
``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03
-------------------------------------------- -------------------------------- ------------- -------------
Designated initializers (N494) C99 C89
Expand Down Expand Up @@ -2928,7 +2931,7 @@ Query for this feature with ``__has_builtin(__builtin_dump_struct)``
``__builtin_shufflevector`` is used to express generic vector
permutation/shuffle/swizzle operations. This builtin is also very important
for the implementation of various target-specific header files like
``<xmmintrin.h>``.
``<xmmintrin.h>``. This builtin can be used within constant expressions.
**Syntax**:
Expand All @@ -2955,7 +2958,7 @@ for the implementation of various target-specific header files like
// Concatenate every other element of 8-element vectors V1 and V2.
__builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
// Shuffle v1 with some elements being undefined
// Shuffle v1 with some elements being undefined. Not allowed in constexpr.
__builtin_shufflevector(v1, v1, 3, -1, 1, -1)
**Description**:
Expand All @@ -2968,6 +2971,7 @@ starting with the first vector, continuing into the second vector. Thus, if
``vec1`` is a 4-element vector, index 5 would refer to the second element of
``vec2``. An index of -1 can be used to indicate that the corresponding element
in the returned vector is a don't care and can be optimized by the backend.
Values of -1 are not supported in constant expressions.
The result of ``__builtin_shufflevector`` is a vector with the same element
type as ``vec1``/``vec2`` but that has an element count equal to the number of
Expand All @@ -2982,7 +2986,8 @@ Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
``__builtin_convertvector`` is used to express generic vector
type-conversion operations. The input vector and the output vector
type must have the same number of elements.
type must have the same number of elements. This builtin can be used within
constant expressions.
**Syntax**:
Expand Down Expand Up @@ -5572,3 +5577,25 @@ but the expression has no runtime effects.
Type- and value-dependent expressions are not supported yet.
This facility is designed to aid with testing name lookup machinery.
Predefined Macros
=================
`__GCC_DESTRUCTIVE_SIZE` and `__GCC_CONSTRUCTIVE_SIZE`
------------------------------------------------------
Specify the mimum offset between two objects to avoid false sharing and the
maximum size of contiguous memory to promote true sharing, respectively. These
macros are predefined in all C and C++ language modes, but can be redefined on
the command line with ``-D`` to specify different values as needed or can be
undefined on the command line with ``-U`` to disable support for the feature.
**Note: the values the macros expand to are not guaranteed to be stable. They
are are affected by architectures and CPU tuning flags, can change between
releases of Clang and will not match the values defined by other compilers such
as GCC.**
Compiling different TUs depending on these flags (including use of
``std::hardware_constructive_interference`` or
``std::hardware_destructive_interference``) with different compilers, macro
definitions, or architecture flags will lead to ODR violations and should be
avoided.
22 changes: 17 additions & 5 deletions clang/docs/LibTooling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,22 @@ and automatic location of the compilation database using source files paths.
#include "llvm/Support/CommandLine.h"

using namespace clang::tooling;
using namespace llvm;

// Apply a custom category to all command-line options so that they are the
// only ones displayed.
static llvm::cl::OptionCategory MyToolCategory("my-tool options");
static cl::OptionCategory MyToolCategory("my-tool options");

int main(int argc, const char **argv) {
// CommonOptionsParser constructor will parse arguments and create a
// CompilationDatabase. In case of error it will terminate the program.
CommonOptionsParser OptionsParser(argc, argv, MyToolCategory);
// CommonOptionsParser::create will parse arguments and create a
// CompilationDatabase.
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);
if (!ExpectedParser) {
// Fail gracefully for unsupported options.
llvm::errs() << ExpectedParser.takeError();
return 1;
}
CommonOptionsParser& OptionsParser = ExpectedParser.get();
// Use OptionsParser.getCompilations() and OptionsParser.getSourcePathList()
// to retrieve CompilationDatabase and the list of input file paths.
Expand Down Expand Up @@ -133,7 +140,12 @@ version of this example tool is also checked into the clang tree at
static cl::extrahelp MoreHelp("\nMore help text...\n");

int main(int argc, const char **argv) {
CommonOptionsParser OptionsParser(argc, argv, MyToolCategory);
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);
if (!ExpectedParser) {
llvm::errs() << ExpectedParser.takeError();
return 1;
}
CommonOptionsParser& OptionsParser = ExpectedParser.get();
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>().get());
Expand Down
4 changes: 3 additions & 1 deletion clang/docs/OpenMPSupport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,9 @@ implementation.
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | dispatch construct and function variant argument adjustment | :part:`worked on` | D99537, D99679 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | assume and assumes directives | :part:`worked on` | |
| misc | assumes directives | :part:`worked on` | |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | assume directive | :part:`worked on` | |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | nothing directive | :good:`done` | D123286 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
Expand Down
75 changes: 75 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ ABI Changes in This Version
MSVC uses a different mangling for these objects, compatibility is not affected.
(#GH85423).

- Fixed Microsoft calling convention for returning certain classes with a
templated constructor. If a class has a templated constructor, it should
be returned indirectly even if it meets all the other requirements for
returning a class in a register. This affects some uses of std::pair.
(#GH86384).

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

Expand Down Expand Up @@ -90,6 +96,18 @@ C++ Language Changes
--------------------
- Implemented ``_BitInt`` literal suffixes ``__wb`` or ``__WB`` as a Clang extension with ``unsigned`` modifiers also allowed. (#GH85223).

C++17 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Clang now exposes ``__GCC_DESTRUCTIVE_SIZE`` and ``__GCC_CONSTRUCTIVE_SIZE``
predefined macros to support standard library implementations of
``std::hardware_destructive_interference_size`` and
``std::hardware_constructive_interference_size``, respectively. These macros
are predefined in all C and C++ language modes. The values the macros
expand to are not stable between releases of Clang and do not need to match
the values produced by GCC, so these macros should not be used from header
files because they may not be stable across multiple TUs (the values may vary
based on compiler version as well as CPU tuning). #GH60174

C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -131,6 +149,9 @@ C++2c Feature Support

- Implemented `P2573R2: = delete("should have a reason"); <https://wg21.link/P2573R2>`_

- Implemented `P0609R3: Attributes for Structured Bindings <https://wg21.link/P0609R3>`_

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

Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -207,6 +228,20 @@ Non-comprehensive list of changes in this release
- ``__typeof_unqual__`` is available in all C modes as an extension, which behaves
like ``typeof_unqual`` from C23, similar to ``__typeof__`` and ``typeof``.

- ``__builtin_reduce_{add|mul|xor|or|and|min|max}`` builtins now support scalable vectors.

* Shared libraries linked with either the ``-ffast-math``, ``-Ofast``, or
``-funsafe-math-optimizations`` flags will no longer enable flush-to-zero
floating-point mode by default. This decision can be overridden with use of
``-mdaz-ftz``. This behavior now matches GCC's behavior.
(`#57589 <https://github.com/llvm/llvm-project/issues/57589>`_)

* ``-fdenormal-fp-math=preserve-sign`` is no longer implied by ``-ffast-math``
on x86 systems.

- Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may
now be used within constant expressions.

New Compiler Flags
------------------
- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and
Expand All @@ -221,6 +256,10 @@ New Compiler Flags
- ``-fexperimental-modules-reduced-bmi`` enables the Reduced BMI for C++20 named modules.
See the document of standard C++ modules for details.

- ``-fexperimental-late-parse-attributes`` enables an experimental feature to
allow late parsing certain attributes in specific contexts where they would
not normally be late parsed.

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

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

- Clang now diagnoses requires expressions with explicit object parameters.

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

.. code-block:: c++

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

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

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

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

- When performing mixed arithmetic between ``_Complex`` floating-point types and integers,
Clang now correctly promotes the integer to its corresponding real floating-point
type only rather than to the complex type (e.g. ``_Complex float / int`` is now evaluated
Expand All @@ -436,6 +490,10 @@ Bug Fixes in This Version

- Fixed an assertion failure on invalid InitListExpr in C89 mode (#GH88008).

- Fixed missing destructor calls when we branch from middle of an expression.
This could happen through a branch in stmt-expr or in an expression containing a coroutine
suspension. Fixes (#GH63818) (#GH88478).

- Clang will no longer diagnose an erroneous non-dependent ``switch`` condition
during instantiation, and instead will only diagnose it once, during checking
of the function template.
Expand Down Expand Up @@ -564,6 +622,14 @@ Bug Fixes to C++ Support
- Fixed a crash when trying to evaluate a user-defined ``static_assert`` message whose ``size()``
function returns a large or negative value. Fixes (#GH89407).
- Fixed a use-after-free bug in parsing of type constraints with default arguments that involve lambdas. (#GH67235)
- Fixed bug in which the body of a consteval lambda within a template was not parsed as within an
immediate function context.
- Fix CTAD for ``std::initializer_list``. This allows ``std::initializer_list{1, 2, 3}`` to be deduced as
``std::initializer_list<int>`` as intended.
- Fix a bug on template partial specialization whose template parameter is `decltype(auto)`.
- Fix a bug on template partial specialization with issue on deduction of nontype template parameter
whose type is `decltype(auto)`. Fixes (#GH68885).
- Clang now correctly treats the noexcept-specifier of a friend function to be a complete-class context.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -616,6 +682,10 @@ Arm and AArch64 Support
* Arm Cortex-A78AE (cortex-a78ae).
* Arm Cortex-A520AE (cortex-a520ae).
* Arm Cortex-A720AE (cortex-a720ae).
* Arm Cortex-R82AE (cortex-r82ae).
* Arm Neoverse-N3 (neoverse-n3).
* Arm Neoverse-V3 (neoverse-v3).
* Arm Neoverse-V3AE (neoverse-v3ae).

Android Support
^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -672,6 +742,11 @@ AIX Support
WebAssembly Support
^^^^^^^^^^^^^^^^^^^

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

AVR Support
^^^^^^^^^^^

Expand Down
Loading