diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 77ba81c58c5d63f7e5e054d9503e882afd3ae468..76b8266cae87c4b0b3fbf90e4bf72626aad7c9f3 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -125,3 +125,6 @@ clang/test/AST/Interp/ @tbaederr
/llvm/**/TextAPI/ @cyndyishida
/clang/**/InstallAPI/ @cyndyishida
/clang/tools/clang-installapi/ @cyndyishida
+
+# ExtractAPI
+/clang/**/ExtractAPI @daniel-grumberg
diff --git a/.github/workflows/email-check.yaml b/.github/workflows/email-check.yaml
index ac53b5e527b0949020e0e73d90def5d2b6295cd0..8f32d020975f5d70e7eead9c34a0ea86fb836e81 100644
--- a/.github/workflows/email-check.yaml
+++ b/.github/workflows/email-check.yaml
@@ -1,7 +1,7 @@
name: "Check for private emails used in PRs"
on:
- pull_request_target:
+ pull_request:
types:
- opened
@@ -10,8 +10,6 @@ permissions:
jobs:
validate_email:
- permissions:
- pull-requests: write
runs-on: ubuntu-latest
if: github.repository == 'llvm/llvm-project'
steps:
@@ -25,20 +23,24 @@ jobs:
run: |
git log -1
echo "EMAIL=$(git show -s --format='%ae' HEAD~0)" >> $GITHUB_OUTPUT
+ # Create empty comment file
+ echo "[]" > comments
- name: Validate author email
if: ${{ endsWith(steps.author.outputs.EMAIL, 'noreply.github.com') }}
- uses: actions/github-script@v6
env:
- EMAIL: ${{ steps.author.outputs.EMAIL }}
+ COMMENT: >-
+ ⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
+ Please turn off [Keep my email addresses private](https://github.com/settings/emails) setting in your account.
+ See [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information.
+ run: |
+ cat << EOF > comments
+ [{"body" : "$COMMENT"}]
+ EOF
+
+ - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0
+ if: always()
with:
- script: |
- const { EMAIL } = process.env
- await github.rest.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: `⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
- Please turn off [Keep my email addresses private](https://github.com/settings/emails) setting in your account.
- See [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information.
- `})
+ name: workflow-args
+ path: |
+ comments
diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml
index 4a564a5076bac9a7855d69b59a1a60f088300163..e003be006c4e15405bd977e277b0f9a64e69d2af 100644
--- a/.github/workflows/issue-write.yml
+++ b/.github/workflows/issue-write.yml
@@ -2,7 +2,9 @@ name: Comment on an issue
on:
workflow_run:
- workflows: ["Check code formatting"]
+ workflows:
+ - "Check code formatting"
+ - "Check for private emails used in PRs"
types:
- completed
diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml
index 4a881ef5ff56af432500413950890ee8d6563dbc..1e9367732e591118445fef2c69acf3339c2cbf5d 100644
--- a/.github/workflows/libcxx-build-and-test.yaml
+++ b/.github/workflows/libcxx-build-and-test.yaml
@@ -38,11 +38,11 @@ env:
# LLVM POST-BRANCH bump version
# LLVM POST-BRANCH add compiler test for ToT - 1, e.g. "Clang 17"
# LLVM RELEASE bump remove compiler ToT - 3, e.g. "Clang 15"
- LLVM_HEAD_VERSION: "18" # Used compiler, update POST-BRANCH.
- LLVM_PREVIOUS_VERSION: "17"
- LLVM_OLDEST_VERSION: "16"
+ LLVM_HEAD_VERSION: "19" # Used compiler, update POST-BRANCH.
+ LLVM_PREVIOUS_VERSION: "18"
+ LLVM_OLDEST_VERSION: "17"
GCC_STABLE_VERSION: "13"
- LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-18"
+ LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-19"
CLANG_CRASH_DIAGNOSTICS_DIR: "crash_diagnostics"
@@ -59,8 +59,8 @@ jobs:
'generic-cxx26',
'generic-modules'
]
- cc: [ 'clang-18' ]
- cxx: [ 'clang++-18' ]
+ cc: [ 'clang-19' ]
+ cxx: [ 'clang++-19' ]
clang_tidy: [ 'ON' ]
include:
- config: 'generic-gcc'
@@ -100,22 +100,22 @@ jobs:
'generic-cxx20',
'generic-cxx23'
]
- cc: [ 'clang-18' ]
- cxx: [ 'clang++-18' ]
+ cc: [ 'clang-19' ]
+ cxx: [ 'clang++-19' ]
clang_tidy: [ 'ON' ]
include:
- config: 'generic-gcc-cxx11'
cc: 'gcc-13'
cxx: 'g++-13'
clang_tidy: 'OFF'
- - config: 'generic-cxx23'
- cc: 'clang-16'
- cxx: 'clang++-16'
- clang_tidy: 'OFF'
- config: 'generic-cxx23'
cc: 'clang-17'
cxx: 'clang++-17'
clang_tidy: 'OFF'
+ - config: 'generic-cxx26'
+ cc: 'clang-18'
+ cxx: 'clang++-18'
+ clang_tidy: 'ON'
steps:
- uses: actions/checkout@v4
- name: ${{ matrix.config }}
@@ -186,8 +186,8 @@ jobs:
- name: ${{ matrix.config }}
run: libcxx/utils/ci/run-buildbot ${{ matrix.config }}
env:
- CC: clang-18
- CXX: clang++-18
+ CC: clang-19
+ CXX: clang++-19
ENABLE_CLANG_TIDY: "OFF"
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
if: always()
diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml
index 54dfe3aadbb423d98b106ea02d9f4f09e25574c3..10b18f245d8965a69251038f44f1505fc40c0cf0 100644
--- a/.github/workflows/pr-code-format.yml
+++ b/.github/workflows/pr-code-format.yml
@@ -33,7 +33,7 @@ jobs:
- name: Fetch code formatting utils
uses: actions/checkout@v4
with:
- reository: ${{ github.repository }}
+ repository: ${{ github.repository }}
ref: ${{ github.base_ref }}
sparse-checkout: |
llvm/utils/git/requirements_formatting.txt
diff --git a/bolt/include/bolt/Profile/BoltAddressTranslation.h b/bolt/include/bolt/Profile/BoltAddressTranslation.h
index 92c23b9d909b125b42dbfc47dda218ee2768d976..6a0a477f27583fecf56e57c6ee8f43a32de7ba81 100644
--- a/bolt/include/bolt/Profile/BoltAddressTranslation.h
+++ b/bolt/include/bolt/Profile/BoltAddressTranslation.h
@@ -124,11 +124,12 @@ public:
std::unordered_map>
getBFBranches(uint64_t FuncOutputAddress) const;
- /// For a given \p Symbol in the output binary, returns a corresponding pair
- /// of parent BinaryFunction and secondary entry point in it.
+ /// For a given \p Symbol in the output binary and known \p InputOffset
+ /// return a corresponding pair of parent BinaryFunction and secondary entry
+ /// point in it.
std::pair
translateSymbol(const BinaryContext &BC, const MCSymbol &Symbol,
- uint32_t Offset) const;
+ uint32_t InputOffset) const;
private:
/// Helper to update \p Map by inserting one or more BAT entries reflecting
@@ -165,7 +166,8 @@ private:
/// Map a function to its secondary entry points vector
std::unordered_map> SecondaryEntryPointsMap;
- /// Returns a secondary entry point id for a given \p Address and \p Offset.
+ /// Return a secondary entry point ID for a function located at \p Address and
+ /// \p Offset within that function.
unsigned getSecondaryEntryPointId(uint64_t Address, uint32_t Offset) const;
/// Links outlined cold bocks to their original function
diff --git a/bolt/lib/Profile/BoltAddressTranslation.cpp b/bolt/lib/Profile/BoltAddressTranslation.cpp
index 90c62c13dcaac7ca72ecfe74f496340c62b2be52..59d499f97be726127b49971372836134869fcb26 100644
--- a/bolt/lib/Profile/BoltAddressTranslation.cpp
+++ b/bolt/lib/Profile/BoltAddressTranslation.cpp
@@ -208,7 +208,7 @@ void BoltAddressTranslation::writeMaps(std::map &Maps,
LLVM_DEBUG(dbgs() << "Hash: " << formatv("{0:x}\n", BFHash));
OS.write(reinterpret_cast(&BFHash), 8);
// Number of basic blocks
- size_t NumBasicBlocks = getBBHashMap(HotInputAddress).getNumBasicBlocks();
+ size_t NumBasicBlocks = NumBasicBlocksMap[HotInputAddress];
LLVM_DEBUG(dbgs() << "Basic blocks: " << NumBasicBlocks << '\n');
encodeULEB128(NumBasicBlocks, OS);
// Secondary entry points
@@ -426,8 +426,9 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
for (const auto &MapEntry : Maps) {
const uint64_t Address = MapEntry.first;
const uint64_t HotAddress = fetchParentAddress(Address);
+ const bool IsHotFunction = HotAddress == 0;
OS << "Function Address: 0x" << Twine::utohexstr(Address);
- if (HotAddress == 0)
+ if (IsHotFunction)
OS << formatv(", hash: {0:x}", getBFHash(Address));
OS << "\n";
OS << "BB mappings:\n";
@@ -444,6 +445,8 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
OS << formatv(" hash: {0:x}", BBHashMap.getBBHash(Val));
OS << "\n";
}
+ if (IsHotFunction)
+ OS << "NumBlocks: " << NumBasicBlocksMap[Address] << '\n';
if (SecondaryEntryPointsMap.count(Address)) {
const std::vector &SecondaryEntryPoints =
SecondaryEntryPointsMap[Address];
@@ -575,6 +578,7 @@ void BoltAddressTranslation::saveMetadata(BinaryContext &BC) {
// Set BF/BB metadata
for (const BinaryBasicBlock &BB : BF)
BBHashMap.addEntry(BB.getInputOffset(), BB.getIndex(), BB.getHash());
+ NumBasicBlocksMap.emplace(BF.getAddress(), BF.size());
}
}
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index d0289d551c6a693d9984c20937199655052c13ef..71824e2cc0e97a5d15589487e9728d32d97edc19 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -2386,9 +2386,40 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
YamlCSI.Count = BI.Branches;
YamlCSI.Mispreds = BI.Mispreds;
YamlCSI.Offset = BranchOffset - Offset;
- if (BinaryData *BD = BC.getBinaryDataByName(CallToLoc.Name))
- YAMLProfileWriter::setCSIDestination(BC, YamlCSI, BD->getSymbol(),
- BAT, CallToLoc.Offset);
+ BinaryData *CallTargetBD = BC.getBinaryDataByName(CallToLoc.Name);
+ if (!CallTargetBD) {
+ YamlBB.CallSites.emplace_back(YamlCSI);
+ continue;
+ }
+ uint64_t CallTargetAddress = CallTargetBD->getAddress();
+ BinaryFunction *CallTargetBF =
+ BC.getBinaryFunctionAtAddress(CallTargetAddress);
+ if (!CallTargetBF) {
+ YamlBB.CallSites.emplace_back(YamlCSI);
+ continue;
+ }
+ // Calls between hot and cold fragments must be handled in
+ // fixupBATProfile.
+ assert(CallTargetBF != BF && "invalid CallTargetBF");
+ YamlCSI.DestId = CallTargetBF->getFunctionNumber();
+ if (CallToLoc.Offset) {
+ if (BAT->isBATFunction(CallTargetAddress)) {
+ LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Unsupported secondary "
+ "entry point in BAT function "
+ << CallToLoc.Name << '\n');
+ } else if (const BinaryBasicBlock *CallTargetBB =
+ CallTargetBF->getBasicBlockAtOffset(
+ CallToLoc.Offset)) {
+ // Only record true call information, ignoring returns (normally
+ // won't have a target basic block) and jumps to the landing
+ // pads (not an entry point).
+ if (CallTargetBB->isEntryPoint()) {
+ YamlCSI.EntryDiscriminator =
+ CallTargetBF->getEntryIDForSymbol(
+ CallTargetBB->getLabel());
+ }
+ }
+ }
YamlBB.CallSites.emplace_back(YamlCSI);
}
}
diff --git a/bolt/lib/Profile/YAMLProfileWriter.cpp b/bolt/lib/Profile/YAMLProfileWriter.cpp
index f1cdfc09a8a2f764b85867084052b1aeba6cad7b..ef04ba0d21ad75cf29421c24922738e9f0cba1d9 100644
--- a/bolt/lib/Profile/YAMLProfileWriter.cpp
+++ b/bolt/lib/Profile/YAMLProfileWriter.cpp
@@ -13,7 +13,6 @@
#include "bolt/Profile/ProfileReaderBase.h"
#include "bolt/Rewrite/RewriteInstance.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/bolt/test/X86/yaml-secondary-entry-discriminator.s b/bolt/test/X86/yaml-secondary-entry-discriminator.s
index 35e9a079ae0def9bbafe7edd55cb4ee0cee32533..78e7e55aa98eba774997e3aa2d99034036a619db 100644
--- a/bolt/test/X86/yaml-secondary-entry-discriminator.s
+++ b/bolt/test/X86/yaml-secondary-entry-discriminator.s
@@ -38,43 +38,10 @@
# RUN: llvm-bolt %t.exe -o %t.bat --data %t.fdata --funcs=func \
# RUN: --split-functions --split-strategy=all --split-all-cold --enable-bat
-# Prepare pre-aggregated profile using %t.bat
-# RUN: link_fdata %s %t.bat %t.preagg PREAGG
-# Strip labels used for pre-aggregated profile
-# RUN: llvm-strip -NLcall -NLindcall %t.bat
-
-# Convert pre-aggregated profile using BAT
-# RUN: perf2bolt %t.bat -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml
-
-# Convert BAT fdata into YAML
-# RUN: llvm-bolt %t.exe -data %t.bat.fdata -w %t.bat.fdata-yaml -o /dev/null
-
-# Check fdata YAML - make sure that a direct call has discriminator field
-# RUN: FileCheck %s --input-file %t.bat.fdata-yaml -check-prefix CHECK-BAT-YAML
-
-# Check BAT YAML - make sure that a direct call has discriminator field
-# RUN: FileCheck %s --input-file %t.bat.yaml --check-prefix CHECK-BAT-YAML
-
-# YAML BAT test of calling BAT secondary entry from BAT function
-# RUN: llvm-bolt %t.exe -o %t.bat2 --data %t.fdata --funcs=main,func \
-# RUN: --split-functions --split-strategy=all --split-all-cold --enable-bat
-
-# CHECK-BAT-YAML: - name: main
-# CHECK-BAT-YAML-NEXT: fid: 2
-# CHECK-BAT-YAML-NEXT: hash: 0xADF270D550151185
-# CHECK-BAT-YAML-NEXT: exec: 0
-# CHECK-BAT-YAML-NEXT: nblocks: 4
-# CHECK-BAT-YAML-NEXT: blocks:
-# CHECK-BAT-YAML: - bid: 1
-# CHECK-BAT-YAML-NEXT: insns: [[#]]
-# CHECK-BAT-YAML-NEXT: hash: 0x36A303CBA4360018
-# CHECK-BAT-YAML-NEXT: calls: [ { off: 0x0, fid: [[#]], disc: 1, cnt: 1 } ]
-
.globl func
.type func, @function
func:
# FDATA: 0 [unknown] 0 1 func 0 1 0
-# PREAGG: B X:0 #func# 1 1
.cfi_startproc
pushq %rbp
movq %rsp, %rbp
@@ -104,16 +71,12 @@ main:
movl $0, -4(%rbp)
testq %rax, %rax
jne Lindcall
-.globl Lcall
Lcall:
call secondary_entry
# FDATA: 1 main #Lcall# 1 secondary_entry 0 1 1
-# PREAGG: B #Lcall# #secondary_entry# 1 1
-.globl Lindcall
Lindcall:
callq *%rax
# FDATA: 1 main #Lindcall# 1 secondary_entry 0 1 1
-# PREAGG: B #Lindcall# #secondary_entry# 1 1
xorl %eax, %eax
addq $16, %rsp
popq %rbp
diff --git a/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp b/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp
index 8020f8cd062510b5ac677cf1d73de8d8c38800f1..b1a18485ce168d2bf94528d1c5a6f453537c6e79 100644
--- a/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp
+++ b/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp
@@ -14,9 +14,9 @@ IgnoredRemoveResultCheck::IgnoredRemoveResultCheck(llvm::StringRef Name,
ClangTidyContext *Context)
: UnusedReturnValueCheck(Name, Context,
{
- "::std::remove",
- "::std::remove_if",
- "::std::unique",
+ "::std::remove$",
+ "::std::remove_if$",
+ "::std::unique$",
}) {
// The constructor for ClangTidyCheck needs to have been called
// before we can access options via Options.get().
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
index e3400f614fa5640784b1d6dee31caade6a5a2c8b..48bca41f4a3b1e87dbd7488617702f17e5f6e15a 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
@@ -7,19 +7,18 @@
//===----------------------------------------------------------------------===//
#include "AvoidReturnWithVoidValueCheck.h"
-#include "clang/AST/Stmt.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
+#include "../utils/BracesAroundStatement.h"
+#include "../utils/LexerUtils.h"
using namespace clang::ast_matchers;
namespace clang::tidy::readability {
-static constexpr auto IgnoreMacrosName = "IgnoreMacros";
-static constexpr auto IgnoreMacrosDefault = true;
+static constexpr char IgnoreMacrosName[] = "IgnoreMacros";
+static const bool IgnoreMacrosDefault = true;
-static constexpr auto StrictModeName = "StrictMode";
-static constexpr auto StrictModeDefault = true;
+static constexpr char StrictModeName[] = "StrictMode";
+static const bool StrictModeDefault = true;
AvoidReturnWithVoidValueCheck::AvoidReturnWithVoidValueCheck(
StringRef Name, ClangTidyContext *Context)
@@ -32,7 +31,10 @@ void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
returnStmt(
hasReturnValue(allOf(hasType(voidType()), unless(initListExpr()))),
- optionally(hasParent(compoundStmt().bind("compound_parent"))))
+ optionally(hasParent(
+ compoundStmt(
+ optionally(hasParent(functionDecl().bind("function_parent"))))
+ .bind("compound_parent"))))
.bind("void_return"),
this);
}
@@ -42,10 +44,30 @@ void AvoidReturnWithVoidValueCheck::check(
const auto *VoidReturn = Result.Nodes.getNodeAs("void_return");
if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID())
return;
- if (!StrictMode && !Result.Nodes.getNodeAs("compound_parent"))
+ const auto *SurroundingBlock =
+ Result.Nodes.getNodeAs("compound_parent");
+ if (!StrictMode && !SurroundingBlock)
return;
- diag(VoidReturn->getBeginLoc(), "return statement within a void function "
- "should not have a specified return value");
+ DiagnosticBuilder Diag = diag(VoidReturn->getBeginLoc(),
+ "return statement within a void function "
+ "should not have a specified return value");
+ const SourceLocation SemicolonPos = utils::lexer::findNextTerminator(
+ VoidReturn->getEndLoc(), *Result.SourceManager, getLangOpts());
+ if (SemicolonPos.isInvalid())
+ return;
+ if (!SurroundingBlock) {
+ const auto BraceInsertionHints = utils::getBraceInsertionsHints(
+ VoidReturn, getLangOpts(), *Result.SourceManager,
+ VoidReturn->getBeginLoc());
+ if (BraceInsertionHints)
+ Diag << BraceInsertionHints.openingBraceFixIt()
+ << BraceInsertionHints.closingBraceFixIt();
+ }
+ Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc());
+ if (!Result.Nodes.getNodeAs("function_parent") ||
+ SurroundingBlock->body_back() != VoidReturn)
+ Diag << FixItHint::CreateInsertion(SemicolonPos.getLocWithOffset(1),
+ " return;", true);
}
void AvoidReturnWithVoidValueCheck::storeOptions(
diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp
index 81ca33cbbdfb4b5461b54b8a0b5903c0d1186942..85bd9c1e4f9a043074963487e72077c55bc089b3 100644
--- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "BracesAroundStatementsCheck.h"
+#include "../utils/BracesAroundStatement.h"
#include "../utils/LexerUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchers.h"
@@ -17,12 +18,10 @@ using namespace clang::ast_matchers;
namespace clang::tidy::readability {
static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
- const ASTContext *Context) {
+ const LangOptions &LangOpts) {
Token Tok;
- SourceLocation Beginning =
- Lexer::GetBeginningOfToken(Loc, SM, Context->getLangOpts());
- const bool Invalid =
- Lexer::getRawToken(Beginning, Tok, SM, Context->getLangOpts());
+ SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
+ const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts);
assert(!Invalid && "Expected a valid token.");
if (Invalid)
@@ -33,64 +32,21 @@ static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
static SourceLocation
forwardSkipWhitespaceAndComments(SourceLocation Loc, const SourceManager &SM,
- const ASTContext *Context) {
+ const LangOptions &LangOpts) {
assert(Loc.isValid());
for (;;) {
while (isWhitespace(*SM.getCharacterData(Loc)))
Loc = Loc.getLocWithOffset(1);
- tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+ tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts);
if (TokKind != tok::comment)
return Loc;
// Fast-forward current token.
- Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+ Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
}
}
-static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM,
- const ASTContext *Context) {
- SourceLocation Loc =
- utils::lexer::getUnifiedEndLoc(S, SM, Context->getLangOpts());
- if (!Loc.isValid())
- return Loc;
-
- // Start searching right after S.
- Loc = Loc.getLocWithOffset(1);
-
- for (;;) {
- assert(Loc.isValid());
- while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) {
- Loc = Loc.getLocWithOffset(1);
- }
-
- if (isVerticalWhitespace(*SM.getCharacterData(Loc))) {
- // EOL, insert brace before.
- break;
- }
- tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
- if (TokKind != tok::comment) {
- // Non-comment token, insert brace before.
- break;
- }
-
- SourceLocation TokEndLoc =
- Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
- SourceRange TokRange(Loc, TokEndLoc);
- StringRef Comment = Lexer::getSourceText(
- CharSourceRange::getTokenRange(TokRange), SM, Context->getLangOpts());
- if (Comment.starts_with("/*") && Comment.contains('\n')) {
- // Multi-line block comment, insert brace before.
- break;
- }
- // else: Trailing comment, insert brace after the newline.
-
- // Fast-forward current token.
- Loc = TokEndLoc;
- }
- return Loc;
-}
-
BracesAroundStatementsCheck::BracesAroundStatementsCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
@@ -124,7 +80,7 @@ void BracesAroundStatementsCheck::check(
} else if (const auto *S = Result.Nodes.getNodeAs("do")) {
checkStmt(Result, S->getBody(), S->getDoLoc(), S->getWhileLoc());
} else if (const auto *S = Result.Nodes.getNodeAs("while")) {
- SourceLocation StartLoc = findRParenLoc(S, SM, Context);
+ SourceLocation StartLoc = findRParenLoc(S, SM, Context->getLangOpts());
if (StartLoc.isInvalid())
return;
checkStmt(Result, S->getBody(), StartLoc);
@@ -133,7 +89,7 @@ void BracesAroundStatementsCheck::check(
if (S->isConsteval())
return;
- SourceLocation StartLoc = findRParenLoc(S, SM, Context);
+ SourceLocation StartLoc = findRParenLoc(S, SM, Context->getLangOpts());
if (StartLoc.isInvalid())
return;
if (ForceBracesStmts.erase(S))
@@ -156,7 +112,7 @@ template
SourceLocation
BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S,
const SourceManager &SM,
- const ASTContext *Context) {
+ const LangOptions &LangOpts) {
// Skip macros.
if (S->getBeginLoc().isMacroID())
return {};
@@ -170,14 +126,14 @@ BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S,
}
SourceLocation PastCondEndLoc =
- Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, Context->getLangOpts());
+ Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, LangOpts);
if (PastCondEndLoc.isInvalid())
return {};
SourceLocation RParenLoc =
- forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, Context);
+ forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, LangOpts);
if (RParenLoc.isInvalid())
return {};
- tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, Context);
+ tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, LangOpts);
if (TokKind != tok::r_paren)
return {};
return RParenLoc;
@@ -188,86 +144,23 @@ BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S,
bool BracesAroundStatementsCheck::checkStmt(
const MatchFinder::MatchResult &Result, const Stmt *S,
SourceLocation StartLoc, SourceLocation EndLocHint) {
-
while (const auto *AS = dyn_cast(S))
S = AS->getSubStmt();
- const SourceManager &SM = *Result.SourceManager;
- const ASTContext *Context = Result.Context;
-
- // 1) If there's a corresponding "else" or "while", the check inserts "} "
- // right before that token.
- // 2) If there's a multi-line block comment starting on the same line after
- // the location we're inserting the closing brace at, or there's a non-comment
- // token, the check inserts "\n}" right before that token.
- // 3) Otherwise the check finds the end of line (possibly after some block or
- // line comments) and inserts "\n}" right before that EOL.
- if (!S || isa(S)) {
- // Already inside braces.
- return false;
- }
-
- // When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt.
- // This NullStmt can be detected according to beginning token.
- const SourceLocation StmtBeginLoc = S->getBeginLoc();
- if (isa(S) && StmtBeginLoc.isValid() &&
- getTokenKind(StmtBeginLoc, SM, Context) == tok::l_brace)
- return false;
-
- if (StartLoc.isInvalid())
- return false;
-
- // Convert StartLoc to file location, if it's on the same macro expansion
- // level as the start of the statement. We also need file locations for
- // Lexer::getLocForEndOfToken working properly.
- StartLoc = Lexer::makeFileCharRange(
- CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM,
- Context->getLangOpts())
- .getBegin();
- if (StartLoc.isInvalid())
- return false;
- StartLoc =
- Lexer::getLocForEndOfToken(StartLoc, 0, SM, Context->getLangOpts());
-
- // StartLoc points at the location of the opening brace to be inserted.
- SourceLocation EndLoc;
- std::string ClosingInsertion;
- if (EndLocHint.isValid()) {
- EndLoc = EndLocHint;
- ClosingInsertion = "} ";
- } else {
- EndLoc = findEndLocation(*S, SM, Context);
- ClosingInsertion = "\n}";
- }
-
- assert(StartLoc.isValid());
-
- // Don't require braces for statements spanning less than certain number of
- // lines.
- if (ShortStatementLines && !ForceBracesStmts.erase(S)) {
- unsigned StartLine = SM.getSpellingLineNumber(StartLoc);
- unsigned EndLine = SM.getSpellingLineNumber(EndLoc);
- if (EndLine - StartLine < ShortStatementLines)
+ const auto BraceInsertionHints = utils::getBraceInsertionsHints(
+ S, Result.Context->getLangOpts(), *Result.SourceManager, StartLoc,
+ EndLocHint);
+ if (BraceInsertionHints) {
+ if (ShortStatementLines && !ForceBracesStmts.erase(S) &&
+ BraceInsertionHints.resultingCompoundLineExtent(*Result.SourceManager) <
+ ShortStatementLines)
return false;
+ auto Diag = diag(BraceInsertionHints.DiagnosticPos,
+ "statement should be inside braces");
+ if (BraceInsertionHints.offersFixIts())
+ Diag << BraceInsertionHints.openingBraceFixIt()
+ << BraceInsertionHints.closingBraceFixIt();
}
-
- auto Diag = diag(StartLoc, "statement should be inside braces");
-
- // Change only if StartLoc and EndLoc are on the same macro expansion level.
- // This will also catch invalid EndLoc.
- // Example: LLVM_DEBUG( for(...) do_something() );
- // In this case fix-it cannot be provided as the semicolon which is not
- // visible here is part of the macro. Adding braces here would require adding
- // another semicolon.
- if (Lexer::makeFileCharRange(
- CharSourceRange::getTokenRange(SourceRange(
- SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))),
- SM, Context->getLangOpts())
- .isInvalid())
- return false;
-
- Diag << FixItHint::CreateInsertion(StartLoc, " {")
- << FixItHint::CreateInsertion(EndLoc, ClosingInsertion);
return true;
}
diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h
index 249aa1aaaa91545549c847912feb3415a381e8cf..4cd37a7b2dd6cc169f9301d6a21b1613748399db 100644
--- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h
@@ -52,7 +52,7 @@ private:
SourceLocation EndLocHint = SourceLocation());
template
SourceLocation findRParenLoc(const IfOrWhileStmt *S, const SourceManager &SM,
- const ASTContext *Context);
+ const LangOptions &LangOpts);
std::optional getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}
diff --git a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
index 67147164946ab405138aeafbb361f490f4382ad6..229e5583846b96c0a4ddc537bc78d7a4467fa355 100644
--- a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
@@ -79,6 +79,10 @@ void DuplicateIncludeCallbacks::InclusionDirective(
bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
+ // Skip includes behind macros
+ if (FilenameRange.getBegin().isMacroID() ||
+ FilenameRange.getEnd().isMacroID())
+ return;
if (llvm::is_contained(Files.back(), FileName)) {
// We want to delete the entire line, so make sure that [Start,End] covers
// everything.
diff --git a/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2a3b7bed08c1e00363d9ad2c899528d8e150f61e
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp
@@ -0,0 +1,168 @@
+//===--- BracesAroundStatement.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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides utilities to put braces around a statement.
+///
+//===----------------------------------------------------------------------===//
+
+#include "BracesAroundStatement.h"
+#include "../utils/LexerUtils.h"
+#include "LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang::tidy::utils {
+
+BraceInsertionHints::operator bool() const { return DiagnosticPos.isValid(); }
+
+bool BraceInsertionHints::offersFixIts() const {
+ return OpeningBracePos.isValid() && ClosingBracePos.isValid();
+}
+
+unsigned BraceInsertionHints::resultingCompoundLineExtent(
+ const SourceManager &SourceMgr) const {
+ return SourceMgr.getSpellingLineNumber(ClosingBracePos) -
+ SourceMgr.getSpellingLineNumber(OpeningBracePos);
+}
+
+FixItHint BraceInsertionHints::openingBraceFixIt() const {
+ return OpeningBracePos.isValid()
+ ? FixItHint::CreateInsertion(OpeningBracePos, " {")
+ : FixItHint();
+}
+
+FixItHint BraceInsertionHints::closingBraceFixIt() const {
+ return ClosingBracePos.isValid()
+ ? FixItHint::CreateInsertion(ClosingBracePos, ClosingBrace)
+ : FixItHint();
+}
+
+static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ Token Tok;
+ SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
+ const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts);
+ assert(!Invalid && "Expected a valid token.");
+
+ if (Invalid)
+ return tok::NUM_TOKENS;
+
+ return Tok.getKind();
+}
+
+static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ SourceLocation Loc = lexer::getUnifiedEndLoc(S, SM, LangOpts);
+ if (!Loc.isValid())
+ return Loc;
+
+ // Start searching right after S.
+ Loc = Loc.getLocWithOffset(1);
+
+ for (;;) {
+ assert(Loc.isValid());
+ while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) {
+ Loc = Loc.getLocWithOffset(1);
+ }
+
+ if (isVerticalWhitespace(*SM.getCharacterData(Loc))) {
+ // EOL, insert brace before.
+ break;
+ }
+ tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts);
+ if (TokKind != tok::comment) {
+ // Non-comment token, insert brace before.
+ break;
+ }
+
+ SourceLocation TokEndLoc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
+ SourceRange TokRange(Loc, TokEndLoc);
+ StringRef Comment = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(TokRange), SM, LangOpts);
+ if (Comment.starts_with("/*") && Comment.contains('\n')) {
+ // Multi-line block comment, insert brace before.
+ break;
+ }
+ // else: Trailing comment, insert brace after the newline.
+
+ // Fast-forward current token.
+ Loc = TokEndLoc;
+ }
+ return Loc;
+}
+
+BraceInsertionHints getBraceInsertionsHints(const Stmt *const S,
+ const LangOptions &LangOpts,
+ const SourceManager &SM,
+ SourceLocation StartLoc,
+ SourceLocation EndLocHint) {
+ // 1) If there's a corresponding "else" or "while", the check inserts "} "
+ // right before that token.
+ // 2) If there's a multi-line block comment starting on the same line after
+ // the location we're inserting the closing brace at, or there's a non-comment
+ // token, the check inserts "\n}" right before that token.
+ // 3) Otherwise the check finds the end of line (possibly after some block or
+ // line comments) and inserts "\n}" right before that EOL.
+ if (!S || isa(S)) {
+ // Already inside braces.
+ return {};
+ }
+
+ // When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt.
+ // This NullStmt can be detected according to beginning token.
+ const SourceLocation StmtBeginLoc = S->getBeginLoc();
+ if (isa(S) && StmtBeginLoc.isValid() &&
+ getTokenKind(StmtBeginLoc, SM, LangOpts) == tok::l_brace)
+ return {};
+
+ if (StartLoc.isInvalid())
+ return {};
+
+ // Convert StartLoc to file location, if it's on the same macro expansion
+ // level as the start of the statement. We also need file locations for
+ // Lexer::getLocForEndOfToken working properly.
+ StartLoc = Lexer::makeFileCharRange(
+ CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM,
+ LangOpts)
+ .getBegin();
+ if (StartLoc.isInvalid())
+ return {};
+ StartLoc = Lexer::getLocForEndOfToken(StartLoc, 0, SM, LangOpts);
+
+ // StartLoc points at the location of the opening brace to be inserted.
+ SourceLocation EndLoc;
+ std::string ClosingInsertion;
+ if (EndLocHint.isValid()) {
+ EndLoc = EndLocHint;
+ ClosingInsertion = "} ";
+ } else {
+ EndLoc = findEndLocation(*S, SM, LangOpts);
+ ClosingInsertion = "\n}";
+ }
+
+ assert(StartLoc.isValid());
+
+ // Change only if StartLoc and EndLoc are on the same macro expansion level.
+ // This will also catch invalid EndLoc.
+ // Example: LLVM_DEBUG( for(...) do_something() );
+ // In this case fix-it cannot be provided as the semicolon which is not
+ // visible here is part of the macro. Adding braces here would require adding
+ // another semicolon.
+ if (Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(SourceRange(
+ SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))),
+ SM, LangOpts)
+ .isInvalid())
+ return {StartLoc};
+ return {StartLoc, EndLoc, ClosingInsertion};
+}
+
+} // namespace clang::tidy::utils
diff --git a/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h
new file mode 100644
index 0000000000000000000000000000000000000000..cb1c06c7aa1a1a9d5bdd56cd805aa26f19e56c8d
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h
@@ -0,0 +1,75 @@
+//===--- BracesAroundStatement.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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides utilities to put braces around a statement.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+
+namespace clang::tidy::utils {
+
+/// A provider of fix-it hints to insert opening and closing braces. An instance
+/// of this type is the result of calling `getBraceInsertionsHints` below.
+struct BraceInsertionHints {
+ /// The position of a potential diagnostic. It coincides with the position of
+ /// the opening brace to insert, but can also just be the place to show a
+ /// diagnostic in case braces cannot be inserted automatically.
+ SourceLocation DiagnosticPos;
+
+ /// Constructor for a no-hint.
+ BraceInsertionHints() = default;
+
+ /// Constructor for a valid hint that cannot insert braces automatically.
+ BraceInsertionHints(SourceLocation DiagnosticPos)
+ : DiagnosticPos(DiagnosticPos) {}
+
+ /// Constructor for a hint offering fix-its for brace insertion. Both
+ /// positions must be valid.
+ BraceInsertionHints(SourceLocation OpeningBracePos,
+ SourceLocation ClosingBracePos, std::string ClosingBrace)
+ : DiagnosticPos(OpeningBracePos), OpeningBracePos(OpeningBracePos),
+ ClosingBracePos(ClosingBracePos), ClosingBrace(ClosingBrace) {
+ assert(offersFixIts());
+ }
+
+ /// Indicates whether the hint provides at least the position of a diagnostic.
+ operator bool() const;
+
+ /// Indicates whether the hint provides fix-its to insert braces.
+ bool offersFixIts() const;
+
+ /// The number of lines between the inserted opening brace and its closing
+ /// counterpart.
+ unsigned resultingCompoundLineExtent(const SourceManager &SourceMgr) const;
+
+ /// Fix-it to insert an opening brace.
+ FixItHint openingBraceFixIt() const;
+
+ /// Fix-it to insert a closing brace.
+ FixItHint closingBraceFixIt() const;
+
+private:
+ SourceLocation OpeningBracePos;
+ SourceLocation ClosingBracePos;
+ std::string ClosingBrace;
+};
+
+/// Create fix-it hints for braces that wrap the given statement when applied.
+/// The algorithm computing them respects comment before and after the statement
+/// and adds line breaks before the braces accordingly.
+BraceInsertionHints
+getBraceInsertionsHints(const Stmt *const S, const LangOptions &LangOpts,
+ const SourceManager &SM, SourceLocation StartLoc,
+ SourceLocation EndLocHint = SourceLocation());
+
+} // namespace clang::tidy::utils
diff --git a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
index f0160fa9df74879429e6f6be554d43bf633af0d6..9cff7d475425d792c2c2f373a3e88d34f7216513 100644
--- a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangTidyUtils
Aliasing.cpp
ASTUtils.cpp
+ BracesAroundStatement.cpp
DeclRefExprUtils.cpp
DesignatedInitializers.cpp
ExceptionAnalyzer.cpp
diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp
index 5b8128fca62668ca555f049b7652369cd11be39e..fddfffe7523d9516037e310bd0d20b0c9520d100 100644
--- a/clang-tools-extra/clangd/CompileCommands.cpp
+++ b/clang-tools-extra/clangd/CompileCommands.cpp
@@ -466,7 +466,8 @@ llvm::ArrayRef ArgStripper::rulesFor(llvm::StringRef Arg) {
static constexpr llvm::ArrayRef NAME( \
NAME##_init, std::size(NAME##_init) - 1);
#define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
- FLAGS, VISIBILITY, PARAM, HELP, METAVAR, VALUES) \
+ FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \
+ METAVAR, VALUES) \
Prefixes[DriverID::OPT_##ID] = PREFIX;
#include "clang/Driver/Options.inc"
#undef OPTION
@@ -478,7 +479,8 @@ llvm::ArrayRef ArgStripper::rulesFor(llvm::StringRef Arg) {
const void *AliasArgs;
} AliasTable[] = {
#define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
- FLAGS, VISIBILITY, PARAM, HELP, METAVAR, VALUES) \
+ FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \
+ METAVAR, VALUES) \
{DriverID::OPT_##ID, DriverID::OPT_##ALIAS, ALIASARGS},
#include "clang/Driver/Options.inc"
#undef OPTION
diff --git a/clang-tools-extra/clangd/IncludeCleaner.h b/clang-tools-extra/clangd/IncludeCleaner.h
index 387763de340767be7e3cf8598db2b1a6c7076fd5..624e2116be7da3015816dfec628d8de6ac7f363c 100644
--- a/clang-tools-extra/clangd/IncludeCleaner.h
+++ b/clang-tools-extra/clangd/IncludeCleaner.h
@@ -62,15 +62,6 @@ issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code,
const ThreadsafeFS &TFS,
HeaderFilter IgnoreHeader = {});
-/// Affects whether standard library includes should be considered for
-/// removal. This is off by default for now due to implementation limitations:
-/// - macros are not tracked
-/// - symbol names without a unique associated header are not tracked
-/// - references to std-namespaced C types are not properly tracked:
-/// instead of std::size_t -> we see ::size_t ->
-/// FIXME: remove this hack once the implementation is good enough.
-void setIncludeCleanerAnalyzesStdlib(bool B);
-
/// Converts the clangd include representation to include-cleaner
/// include representation.
include_cleaner::Includes convertIncludes(const ParsedAST &);
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 309b844615a1212c4983815ae6eabee086e68e3c..2babb1406b97765f96190c7fa739e5fa738cccea 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -210,6 +210,10 @@ Changes in existing checks
- Improved :doc:`google-runtime-int `
check performance through optimizations.
+- Improved :doc:`hicpp-ignored-remove-result `
+ check by ignoring other functions with same prefixes as the target specific
+ functions.
+
- Improved :doc:`llvm-header-guard
` check by replacing the local
option `HeaderFileExtensions` by the global option of the same name.
@@ -251,6 +255,14 @@ Changes in existing checks
analyzed, se the check now handles the common patterns
`const auto e = (*vector_ptr)[i]` and `const auto e = vector_ptr->at(i);`.
+- Improved :doc:`readability-avoid-return-with-void-value
+ ` check by adding
+ fix-its.
+
+- Improved :doc:`readability-duplicate-include
+ ` check by excluding include
+ directives that form the filename using macro.
+
- Improved :doc:`readability-identifier-naming
` check in `GetConfigPerFile`
mode by resolving symbolic links to header files. Fixed handling of Hungarian
diff --git a/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp b/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp
index b068f08590989394dc5702f310515d9c4b7f8793..fc431024303ab2d39f1b2d50fbba01503b3b1ead 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp
@@ -15,6 +15,10 @@ ForwardIt unique(ForwardIt, ForwardIt);
template
InputIt find(InputIt, InputIt, const T&);
+struct unique_disposable {
+ void* release();
+};
+
class error_code {
};
@@ -63,4 +67,6 @@ void noWarning() {
// bugprone-unused-return-value's checked return types.
errorFunc();
(void) errorFunc();
+
+ std::unique_disposable{}.release();
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
index f00407c99ce57021a4be3fcad13feaa9bbd24140..7c948dba3e8f7c0d4991270f3647761ec3de3dbb 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
@@ -12,23 +12,30 @@ void f2() {
return f1();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f1();
}
void f3(bool b) {
if (b) return f1();
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: if (b) { f1(); return;
+ // CHECK-NEXT: }
return f2();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f2();
+ // CHECK-FIXES-LENIENT: f2();
}
template
T f4() {}
void f5() {
- return f4();
- // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
- // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ { return f4(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:7: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: { f4(); return; }
+ // CHECK-FIXES-LENIENT: { f4(); return; }
}
void f6() { return; }
@@ -41,6 +48,8 @@ void f9() {
return (void)f7();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: (void)f7();
+ // CHECK-FIXES-LENIENT: (void)f7();
}
#define RETURN_VOID return (void)1
@@ -50,12 +59,12 @@ void f10() {
// CHECK-MESSAGES-INCLUDE-MACROS: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
}
-template
+template
struct C {
C(A) {}
};
-template
+template
C f11() { return {}; }
using VOID = void;
@@ -66,4 +75,36 @@ VOID f13() {
return f12();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f12(); return;
+ // CHECK-FIXES-LENIENT: f12(); return;
+ (void)1;
+}
+
+void f14() {
+ return /* comment */ f1() /* comment */ ;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: /* comment */ f1() /* comment */ ; return;
+ // CHECK-FIXES-LENIENT: /* comment */ f1() /* comment */ ; return;
+ (void)1;
+}
+
+void f15() {
+ return/*comment*/f1()/*comment*/;//comment
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: /*comment*/f1()/*comment*/; return;//comment
+ // CHECK-FIXES-LENIENT: /*comment*/f1()/*comment*/; return;//comment
+ (void)1;
+}
+
+void f16(bool b) {
+ if (b) return f1();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: if (b) { f1(); return;
+ // CHECK-NEXT: }
+ else return f2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: else { f2(); return;
+ // CHECK-NEXT: }
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp
index dd954c705514fb777bb5e0570623f076fb5a7070..2119602ba454b49d111524fd42730f41e76b8ede 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp
@@ -70,3 +70,18 @@ int r;
// CHECK-FIXES: {{^int q;$}}
// CHECK-FIXES-NEXT: {{^#include $}}
// CHECK-FIXES-NEXT: {{^int r;$}}
+
+namespace Issue_87303 {
+#define RESET_INCLUDE_CACHE
+// Expect no warnings
+
+#define MACRO_FILENAME "duplicate-include.h"
+#include MACRO_FILENAME
+#include "duplicate-include.h"
+
+#define MACRO_FILENAME_2
+#include
+#include MACRO_FILENAME_2
+
+#undef RESET_INCLUDE_CACHE
+} // Issue_87303
diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp
index d0efc5ca7637538859ab4865eaa3e28e44a60bf1..57d930b26e64c0f1920ff932e18e48e279a0ec0e 100644
--- a/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp
@@ -25,7 +25,7 @@
// RUN: not clang-tidy -checks='-*,modernize-use-override' %T/diagnostics/input.cpp -- -DCOMPILATION_ERROR 2>&1 | FileCheck -check-prefix=CHECK6 -implicit-check-not='{{warning:|error:}}' %s
// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %s -- -DMACRO_FROM_COMMAND_LINE -std=c++20 | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s
// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined,clang-diagnostic-literal-conversion' %s -- -DMACRO_FROM_COMMAND_LINE -std=c++20 -Wno-macro-redefined | FileCheck --check-prefix=CHECK7 -implicit-check-not='{{warning:|error:}}' %s
-// RUN: not clang-tidy -checks='-*,modernize-use-override' %s -- -std=c++20 -DPR64602 | FileCheck -check-prefix=CHECK8 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: clang-tidy -checks='-*,modernize-use-override' %s -- -std=c++20 -DPR64602
// CHECK1: error: no input files [clang-diagnostic-error]
// CHECK1: error: no such file or directory: '{{.*}}nonexistent.cpp' [clang-diagnostic-error]
@@ -68,6 +68,4 @@ auto S<>::foo(auto)
{
return 1;
}
-// CHECK8: error: conflicting types for 'foo' [clang-diagnostic-error]
-// CHECK8: note: previous declaration is here
#endif
diff --git a/clang/cmake/caches/Apple-stage2.cmake b/clang/cmake/caches/Apple-stage2.cmake
index 72cdedd611bc9600c0aecbef59060bee7d22b6be..ede256a2da6b8fd6864bd8584aeddf5126dd5bb9 100644
--- a/clang/cmake/caches/Apple-stage2.cmake
+++ b/clang/cmake/caches/Apple-stage2.cmake
@@ -15,6 +15,7 @@ set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
set(LLVM_ENABLE_MODULES ON CACHE BOOL "")
set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
+set(LLVM_ENABLE_EXPORTED_SYMBOLS_IN_EXECUTABLES OFF CACHE BOOL "")
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
set(CLANG_SPAWN_CC1 ON CACHE BOOL "")
set(BUG_REPORT_URL "http://developer.apple.com/bugreporter/" CACHE STRING "")
diff --git a/clang/cmake/caches/Fuchsia.cmake b/clang/cmake/caches/Fuchsia.cmake
index df69d7d0dd414beb8be6752acae171cf6fd5272e..393d97a4cf1a3302db9be62d1982d0f485d52a3b 100644
--- a/clang/cmake/caches/Fuchsia.cmake
+++ b/clang/cmake/caches/Fuchsia.cmake
@@ -71,6 +71,8 @@ set(_FUCHSIA_BOOTSTRAP_PASSTHROUGH
Python3_LIBRARIES
Python3_INCLUDE_DIRS
Python3_RPATH
+ SWIG_DIR
+ SWIG_EXECUTABLE
CMAKE_FIND_PACKAGE_PREFER_CONFIG
CMAKE_SYSROOT
CMAKE_MODULE_LINKER_FLAGS
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 2ee36f24d7ce4b37c4bdf56ba318549b48696a80..39f7cded36edbff5846925aa56319682a04ed476 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3295,6 +3295,21 @@ the configuration (without a prefix: ``Auto``).
+.. _BreakFunctionDefinitionParameters:
+
+**BreakFunctionDefinitionParameters** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ `
+ If ``true``, clang-format will always break before function definition
+ parameters.
+
+ .. code-block:: c++
+
+ true:
+ void functionDefinition(
+ int A, int B) {}
+
+ false:
+ void functionDefinition(int A, int B) {}
+
.. _BreakInheritanceList:
**BreakInheritanceList** (``BreakInheritanceListStyle``) :versionbadge:`clang-format 7` :ref:`¶ `
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 76eaf0bf11c303dc4f0b46c3ff3b75dca65f04fc..28e8ddb3c41c3e9fb87cda31b1a0e4b7897b69c0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -193,6 +193,9 @@ Non-comprehensive list of changes in this release
with support for any unsigned integer type. Like the previous builtins, these
new builtins are constexpr and may be used in constant expressions.
+- ``__typeof_unqual__`` is available in all C modes as an extension, which behaves
+ like ``typeof_unqual`` from C23, similar to ``__typeof__`` and ``typeof``.
+
New Compiler Flags
------------------
@@ -253,6 +256,21 @@ Attribute Changes in Clang
added a new extension query ``__has_extension(swiftcc)`` corresponding to the
``__attribute__((swiftcc))`` attribute.
+- The ``_Nullable`` and ``_Nonnull`` family of type attributes can now apply
+ to certain C++ class types, such as smart pointers:
+ ``void useObject(std::unique_ptr