15 changes: 10 additions & 5 deletions clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ using namespace clang::ast_matchers;
namespace clang::tidy::modernize {

namespace {
AST_MATCHER_P(InitListExpr, initCountLeq, unsigned, N) {
return Node.getNumInits() <= N;
}

// Identical to hasAnyName, except it does not take template specifiers into
// account. This is used to match the functions names as in
// DefaultEmplacyFunctions below without caring about the template types of the
Expand Down Expand Up @@ -205,11 +209,12 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
auto HasConstructExpr = has(ignoringImplicit(SoughtConstructExpr));

// allow for T{} to be replaced, even if no CTOR is declared
auto HasConstructInitListExpr = has(initListExpr(anyOf(
allOf(has(SoughtConstructExpr),
has(cxxConstructExpr(argumentCountIs(0)))),
has(cxxBindTemporaryExpr(has(SoughtConstructExpr),
has(cxxConstructExpr(argumentCountIs(0))))))));
auto HasConstructInitListExpr = has(initListExpr(
initCountLeq(1), anyOf(allOf(has(SoughtConstructExpr),
has(cxxConstructExpr(argumentCountIs(0)))),
has(cxxBindTemporaryExpr(
has(SoughtConstructExpr),
has(cxxConstructExpr(argumentCountIs(0))))))));
auto HasBracedInitListExpr =
anyOf(has(cxxBindTemporaryExpr(HasConstructInitListExpr)),
HasConstructInitListExpr);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//===--- AvoidReturnWithVoidValueCheck.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 "AvoidReturnWithVoidValueCheck.h"
#include "clang/AST/Stmt.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"

using namespace clang::ast_matchers;

namespace clang::tidy::readability {

static constexpr auto IgnoreMacrosName = "IgnoreMacros";
static constexpr auto IgnoreMacrosDefault = true;

static constexpr auto StrictModeName = "StrictMode";
static constexpr auto StrictModeDefault = true;

AvoidReturnWithVoidValueCheck::AvoidReturnWithVoidValueCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IgnoreMacros(
Options.getLocalOrGlobal(IgnoreMacrosName, IgnoreMacrosDefault)),
StrictMode(Options.getLocalOrGlobal(StrictModeName, StrictModeDefault)) {}

void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
returnStmt(
hasReturnValue(allOf(hasType(voidType()), unless(initListExpr()))),
optionally(hasParent(compoundStmt().bind("compound_parent"))))
.bind("void_return"),
this);
}

void AvoidReturnWithVoidValueCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *VoidReturn = Result.Nodes.getNodeAs<ReturnStmt>("void_return");
if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID())
return;
if (!StrictMode && !Result.Nodes.getNodeAs<CompoundStmt>("compound_parent"))
return;
diag(VoidReturn->getBeginLoc(), "return statement within a void function "
"should not have a specified return value");
}

void AvoidReturnWithVoidValueCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, IgnoreMacrosName, IgnoreMacros);
Options.store(Opts, StrictModeName, StrictMode);
}

} // namespace clang::tidy::readability
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//===--- AvoidReturnWithVoidValueCheck.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_AVOIDRETURNWITHVOIDVALUECHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDRETURNWITHVOIDVALUECHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::readability {

/// Finds return statements with `void` values used within functions with `void`
/// result types.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/readability/avoid-return-with-void-value.html
class AvoidReturnWithVoidValueCheck : public ClangTidyCheck {
public:
AvoidReturnWithVoidValueCheck(StringRef Name, ClangTidyContext *Context);

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

private:
std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus;
}
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;

private:
bool IgnoreMacros;
bool StrictMode;
};

} // namespace clang::tidy::readability

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDRETURNWITHVOIDVALUECHECK_H
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 @@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS

add_clang_library(clangTidyReadabilityModule
AvoidConstParamsInDecls.cpp
AvoidReturnWithVoidValueCheck.cpp
AvoidUnconditionalPreprocessorIfCheck.cpp
BracesAroundStatementsCheck.cpp
ConstReturnTypeCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "AvoidConstParamsInDecls.h"
#include "AvoidReturnWithVoidValueCheck.h"
#include "AvoidUnconditionalPreprocessorIfCheck.h"
#include "BracesAroundStatementsCheck.h"
#include "ConstReturnTypeCheck.h"
Expand Down Expand Up @@ -63,6 +64,8 @@ class ReadabilityModule : public ClangTidyModule {
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<AvoidConstParamsInDecls>(
"readability-avoid-const-params-in-decls");
CheckFactories.registerCheck<AvoidReturnWithVoidValueCheck>(
"readability-avoid-return-with-void-value");
CheckFactories.registerCheck<AvoidUnconditionalPreprocessorIfCheck>(
"readability-avoid-unconditional-preprocessor-if");
CheckFactories.registerCheck<BracesAroundStatementsCheck>(
Expand Down
12 changes: 6 additions & 6 deletions clang-tools-extra/clangd/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@ const TemplateTypeParmType *getFunctionPackType(const FunctionDecl *Callee) {
// Returns the template parameter pack type that this parameter was expanded
// from (if in the Args... or Args&... or Args&&... form), if this is the case,
// nullptr otherwise.
const TemplateTypeParmType *getUnderylingPackType(const ParmVarDecl *Param) {
const TemplateTypeParmType *getUnderlyingPackType(const ParmVarDecl *Param) {
const auto *PlainType = Param->getType().getTypePtr();
if (auto *RT = dyn_cast<ReferenceType>(PlainType))
PlainType = RT->getPointeeTypeAsWritten().getTypePtr();
Expand Down Expand Up @@ -793,8 +793,8 @@ class ForwardingCallVisitor
: public RecursiveASTVisitor<ForwardingCallVisitor> {
public:
ForwardingCallVisitor(ArrayRef<const ParmVarDecl *> Parameters)
: Parameters{Parameters}, PackType{getUnderylingPackType(
Parameters.front())} {}
: Parameters{Parameters},
PackType{getUnderlyingPackType(Parameters.front())} {}

bool VisitCallExpr(CallExpr *E) {
auto *Callee = getCalleeDeclOrUniqueOverload(E);
Expand Down Expand Up @@ -859,7 +859,7 @@ class ForwardingCallVisitor
if (const auto *TTPT = getFunctionPackType(Callee)) {
// In this case: Separate the parameters into head, pack and tail
auto IsExpandedPack = [&](const ParmVarDecl *P) {
return getUnderylingPackType(P) == TTPT;
return getUnderlyingPackType(P) == TTPT;
};
ForwardingInfo FI;
FI.Head = MatchingParams.take_until(IsExpandedPack);
Expand Down Expand Up @@ -964,7 +964,7 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) {
if (const auto *TTPT = getFunctionPackType(D)) {
// Split the parameters into head, pack and tail
auto IsExpandedPack = [TTPT](const ParmVarDecl *P) {
return getUnderylingPackType(P) == TTPT;
return getUnderlyingPackType(P) == TTPT;
};
ArrayRef<const ParmVarDecl *> Head = Parameters.take_until(IsExpandedPack);
ArrayRef<const ParmVarDecl *> Pack =
Expand Down Expand Up @@ -1016,7 +1016,7 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) {
}

bool isExpandedFromParameterPack(const ParmVarDecl *D) {
return getUnderylingPackType(D) != nullptr;
return getUnderlyingPackType(D) != nullptr;
}

} // namespace clangd
Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clangd/Hover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,7 @@ void maybeAddSymbolProviders(ParsedAST &AST, HoverInfo &HI,

const SourceManager &SM = AST.getSourceManager();
llvm::SmallVector<include_cleaner::Header> RankedProviders =
include_cleaner::headersForSymbol(Sym, SM, AST.getPragmaIncludes().get());
include_cleaner::headersForSymbol(Sym, SM, &AST.getPragmaIncludes());
if (RankedProviders.empty())
return;

Expand Down Expand Up @@ -1254,7 +1254,7 @@ void maybeAddUsedSymbols(ParsedAST &AST, HoverInfo &HI, const Inclusion &Inc) {
llvm::DenseSet<include_cleaner::Symbol> UsedSymbols;
include_cleaner::walkUsed(
AST.getLocalTopLevelDecls(), collectMacroReferences(AST),
AST.getPragmaIncludes().get(), AST.getPreprocessor(),
&AST.getPragmaIncludes(), AST.getPreprocessor(),
[&](const include_cleaner::SymbolReference &Ref,
llvm::ArrayRef<include_cleaner::Header> Providers) {
if (Ref.RT != include_cleaner::RefType::Explicit ||
Expand Down
36 changes: 3 additions & 33 deletions clang-tools-extra/clangd/IncludeCleaner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
#include <cassert>
#include <iterator>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <utility>
Expand Down Expand Up @@ -237,18 +236,6 @@ removeAllUnusedIncludes(llvm::ArrayRef<Diag> UnusedIncludes) {
Diag.Fixes.front().Edits.begin(),
Diag.Fixes.front().Edits.end());
}

// TODO(hokein): emit a suitable text for the label.
ChangeAnnotation Annotation = {/*label=*/"",
/*needsConfirmation=*/true,
/*description=*/""};
static const ChangeAnnotationIdentifier RemoveAllUnusedID =
"RemoveAllUnusedIncludes";
for (unsigned I = 0; I < RemoveAll.Edits.size(); ++I) {
ChangeAnnotationIdentifier ID = RemoveAllUnusedID + std::to_string(I);
RemoveAll.Edits[I].annotationId = ID;
RemoveAll.Annotations.push_back({ID, Annotation});
}
return RemoveAll;
}

Expand All @@ -268,20 +255,8 @@ addAllMissingIncludes(llvm::ArrayRef<Diag> MissingIncludeDiags) {
Edits.try_emplace(Edit.newText, Edit);
}
}
// FIXME(hokein): emit used symbol reference in the annotation.
ChangeAnnotation Annotation = {/*label=*/"",
/*needsConfirmation=*/true,
/*description=*/""};
static const ChangeAnnotationIdentifier AddAllMissingID =
"AddAllMissingIncludes";
unsigned I = 0;
for (auto &It : Edits) {
ChangeAnnotationIdentifier ID = AddAllMissingID + std::to_string(I++);
for (auto &It : Edits)
AddAllMissing.Edits.push_back(std::move(It.second));
AddAllMissing.Edits.back().annotationId = ID;

AddAllMissing.Annotations.push_back({ID, Annotation});
}
return AddAllMissing;
}
Fix fixAll(const Fix &RemoveAllUnused, const Fix &AddAllMissing) {
Expand All @@ -292,11 +267,6 @@ Fix fixAll(const Fix &RemoveAllUnused, const Fix &AddAllMissing) {
FixAll.Edits.push_back(F);
for (const auto &F : AddAllMissing.Edits)
FixAll.Edits.push_back(F);

for (const auto &A : RemoveAllUnused.Annotations)
FixAll.Annotations.push_back(A);
for (const auto &A : AddAllMissing.Annotations)
FixAll.Annotations.push_back(A);
return FixAll;
}

Expand All @@ -311,7 +281,7 @@ getUnused(ParsedAST &AST,
auto IncludeID = static_cast<IncludeStructure::HeaderID>(*MFI.HeaderID);
if (ReferencedFiles.contains(IncludeID))
continue;
if (!mayConsiderUnused(MFI, AST, AST.getPragmaIncludes().get())) {
if (!mayConsiderUnused(MFI, AST, &AST.getPragmaIncludes())) {
dlog("{0} was not used, but is not eligible to be diagnosed as unused",
MFI.Written);
continue;
Expand Down Expand Up @@ -403,7 +373,7 @@ IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST) {
.getBuiltinDir();
include_cleaner::walkUsed(
AST.getLocalTopLevelDecls(), /*MacroRefs=*/Macros,
AST.getPragmaIncludes().get(), AST.getPreprocessor(),
&AST.getPragmaIncludes(), AST.getPreprocessor(),
[&](const include_cleaner::SymbolReference &Ref,
llvm::ArrayRef<include_cleaner::Header> Providers) {
bool Satisfied = false;
Expand Down
21 changes: 12 additions & 9 deletions clang-tools-extra/clangd/ParsedAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,18 +653,23 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
}

IncludeStructure Includes;
include_cleaner::PragmaIncludes PI;
// If we are using a preamble, copy existing includes.
if (Preamble) {
Includes = Preamble->Includes;
Includes.MainFileIncludes = Patch->preambleIncludes();
// Replay the preamble includes so that clang-tidy checks can see them.
ReplayPreamble::attach(Patch->preambleIncludes(), *Clang,
Patch->modifiedBounds());
PI = *Preamble->Pragmas;
}
// Important: collectIncludeStructure is registered *after* ReplayPreamble!
// Otherwise we would collect the replayed includes again...
// (We can't *just* use the replayed includes, they don't have Resolved path).
Includes.collect(*Clang);
// Same for pragma-includes, we're already inheriting preamble includes, so we
// should only receive callbacks for non-preamble mainfile includes.
PI.record(*Clang);
// Copy over the macros in the preamble region of the main file, and combine
// with non-preamble macros below.
MainFileMacros Macros;
Expand Down Expand Up @@ -735,7 +740,7 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
ParsedAST Result(Filename, Inputs.Version, std::move(Preamble),
std::move(Clang), std::move(Action), std::move(Tokens),
std::move(Macros), std::move(Marks), std::move(ParsedDecls),
std::move(Diags), std::move(Includes));
std::move(Diags), std::move(Includes), std::move(PI));
llvm::move(getIncludeCleanerDiags(Result, Inputs.Contents),
std::back_inserter(Result.Diags));
return std::move(Result);
Expand Down Expand Up @@ -828,23 +833,21 @@ ParsedAST::ParsedAST(PathRef TUPath, llvm::StringRef Version,
syntax::TokenBuffer Tokens, MainFileMacros Macros,
std::vector<PragmaMark> Marks,
std::vector<Decl *> LocalTopLevelDecls,
std::vector<Diag> Diags, IncludeStructure Includes)
std::vector<Diag> Diags, IncludeStructure Includes,
include_cleaner::PragmaIncludes PI)
: TUPath(TUPath), Version(Version), Preamble(std::move(Preamble)),
Clang(std::move(Clang)), Action(std::move(Action)),
Tokens(std::move(Tokens)), Macros(std::move(Macros)),
Marks(std::move(Marks)), Diags(std::move(Diags)),
LocalTopLevelDecls(std::move(LocalTopLevelDecls)),
Includes(std::move(Includes)) {
Resolver = std::make_unique<HeuristicResolver>(getASTContext());
Includes(std::move(Includes)), PI(std::move(PI)),
Resolver(std::make_unique<HeuristicResolver>(getASTContext())) {
assert(this->Clang);
assert(this->Action);
}

std::shared_ptr<const include_cleaner::PragmaIncludes>
ParsedAST::getPragmaIncludes() const {
if (!Preamble)
return nullptr;
return Preamble->Pragmas;
const include_cleaner::PragmaIncludes &ParsedAST::getPragmaIncludes() const {
return PI;
}

std::optional<llvm::StringRef> ParsedAST::preambleVersion() const {
Expand Down
9 changes: 4 additions & 5 deletions clang-tools-extra/clangd/ParsedAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,8 @@ class ParsedAST {
/// Tokens recorded while parsing the main file.
/// (!) does not have tokens from the preamble.
const syntax::TokenBuffer &getTokens() const { return Tokens; }
/// Returns the PramaIncludes from the preamble.
/// Might be null if AST is built without a preamble.
std::shared_ptr<const include_cleaner::PragmaIncludes>
getPragmaIncludes() const;
/// Returns the PramaIncludes for preamble + main file includes.
const include_cleaner::PragmaIncludes &getPragmaIncludes() const;

/// Returns the version of the ParseInputs this AST was built from.
llvm::StringRef version() const { return Version; }
Expand All @@ -129,7 +127,7 @@ class ParsedAST {
std::unique_ptr<FrontendAction> Action, syntax::TokenBuffer Tokens,
MainFileMacros Macros, std::vector<PragmaMark> Marks,
std::vector<Decl *> LocalTopLevelDecls, std::vector<Diag> Diags,
IncludeStructure Includes);
IncludeStructure Includes, include_cleaner::PragmaIncludes PI);
Path TUPath;
std::string Version;
// In-memory preambles must outlive the AST, it is important that this member
Expand Down Expand Up @@ -159,6 +157,7 @@ class ParsedAST {
// top-level decls from the preamble.
std::vector<Decl *> LocalTopLevelDecls;
IncludeStructure Includes;
include_cleaner::PragmaIncludes PI;
std::unique_ptr<HeuristicResolver> Resolver;
};

Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/XRefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1339,7 +1339,7 @@ maybeFindIncludeReferences(ParsedAST &AST, Position Pos,
auto Converted = convertIncludes(AST);
include_cleaner::walkUsed(
AST.getLocalTopLevelDecls(), collectMacroReferences(AST),
AST.getPragmaIncludes().get(), AST.getPreprocessor(),
&AST.getPragmaIncludes(), AST.getPreprocessor(),
[&](const include_cleaner::SymbolReference &Ref,
llvm::ArrayRef<include_cleaner::Header> Providers) {
if (Ref.RT != include_cleaner::RefType::Explicit ||
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/index/FileIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ FileShardedIndex::getShard(llvm::StringRef Uri) const {
SlabTuple indexMainDecls(ParsedAST &AST) {
return indexSymbols(
AST.getASTContext(), AST.getPreprocessor(), AST.getLocalTopLevelDecls(),
&AST.getMacros(), *AST.getPragmaIncludes(),
&AST.getMacros(), AST.getPragmaIncludes(),
/*IsIndexMainAST=*/true, AST.version(), /*CollectMainFileRefs=*/true);
}

Expand Down
8 changes: 4 additions & 4 deletions clang-tools-extra/clangd/index/SymbolCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,8 @@ void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation DefLoc,

// Use the expansion location to get the #include header since this is
// where the symbol is exposed.
IncludeFiles[S.ID] = SM.getDecomposedExpansionLoc(DefLoc).first;
if (FileID FID = SM.getDecomposedExpansionLoc(DefLoc).first; FID.isValid())
IncludeFiles[S.ID] = FID;

// We update providers for a symbol with each occurence, as SymbolCollector
// might run while parsing, rather than at the end of a translation unit.
Expand Down Expand Up @@ -879,16 +880,15 @@ void SymbolCollector::finish() {
const Symbol *S = Symbols.find(SID);
if (!S)
continue;
assert(IncludeFiles.contains(SID));

const auto FID = IncludeFiles.at(SID);
FileID FID = IncludeFiles.lookup(SID);
// Determine if the FID is #include'd or #import'ed.
Symbol::IncludeDirective Directives = Symbol::Invalid;
auto CollectDirectives = shouldCollectIncludePath(S->SymInfo.Kind);
if ((CollectDirectives & Symbol::Include) != 0)
Directives |= Symbol::Include;
// Only allow #import for symbols from ObjC-like files.
if ((CollectDirectives & Symbol::Import) != 0) {
if ((CollectDirectives & Symbol::Import) != 0 && FID.isValid()) {
auto [It, Inserted] = FileToContainsImportsOrObjC.try_emplace(FID);
if (Inserted)
It->second = FilesWithObjCConstructs.contains(FID) ||
Expand Down
15 changes: 15 additions & 0 deletions clang-tools-extra/clangd/test/GH75115.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: rm -rf %t.dir && mkdir -p %t.dir
// RUN: echo '[{"directory": "%/t.dir", "command": "clang --target=x86_64-pc-windows-msvc -x c GH75115.test", "file": "GH75115.test"}]' > %t.dir/compile_commands.json
// RUN: clangd -enable-config=0 --compile-commands-dir=%t.dir -check=%s 2>&1 | FileCheck -strict-whitespace %s

// CHECK: Building preamble...
// CHECK-NEXT: Built preamble
// CHECK-NEXT: Indexing headers...
// CHECK-NEXT: Building AST...
// CHECK-NEXT: Indexing AST...
// CHECK-NEXT: Building inlay hints
// CHECK-NEXT: semantic highlighting
// CHECK-NEXT: Testing features at each token
// CHECK-NEXT: All checks completed, 0 errors

#define assert
68 changes: 0 additions & 68 deletions clang-tools-extra/clangd/test/include-cleaner-batch-fix.test
Original file line number Diff line number Diff line change
Expand Up @@ -157,21 +157,10 @@
# CHECK-NEXT: {
# CHECK-NEXT: "arguments": [
# CHECK-NEXT: {
# CHECK-NEXT: "changeAnnotations": {
# CHECK-NEXT: "AddAllMissingIncludes0": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: },
# CHECK-NEXT: "AddAllMissingIncludes1": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: "documentChanges": [
# CHECK-NEXT: {
# CHECK-NEXT: "edits": [
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "AddAllMissingIncludes0",
# CHECK-NEXT: "newText": "#include {{.*}}bar.h{{.*}}",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand All @@ -185,7 +174,6 @@
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "AddAllMissingIncludes1",
# CHECK-NEXT: "newText": "#include {{.*}}foo.h{{.*}}",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand Down Expand Up @@ -213,29 +201,10 @@
# CHECK-NEXT: {
# CHECK-NEXT: "arguments": [
# CHECK-NEXT: {
# CHECK-NEXT: "changeAnnotations": {
# CHECK-NEXT: "AddAllMissingIncludes0": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: },
# CHECK-NEXT: "AddAllMissingIncludes1": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: },
# CHECK-NEXT: "RemoveAllUnusedIncludes0": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: },
# CHECK-NEXT: "RemoveAllUnusedIncludes1": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: "documentChanges": [
# CHECK-NEXT: {
# CHECK-NEXT: "edits": [
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "RemoveAllUnusedIncludes0",
# CHECK-NEXT: "newText": "",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand All @@ -249,7 +218,6 @@
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "RemoveAllUnusedIncludes1",
# CHECK-NEXT: "newText": "",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand All @@ -263,7 +231,6 @@
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "AddAllMissingIncludes0",
# CHECK-NEXT: "newText": "#include {{.*}}bar.h{{.*}}",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand All @@ -277,7 +244,6 @@
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "AddAllMissingIncludes1",
# CHECK-NEXT: "newText": "#include {{.*}}foo.h{{.*}}",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand Down Expand Up @@ -342,21 +308,10 @@
# CHECK-NEXT: {
# CHECK-NEXT: "arguments": [
# CHECK-NEXT: {
# CHECK-NEXT: "changeAnnotations": {
# CHECK-NEXT: "RemoveAllUnusedIncludes0": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: },
# CHECK-NEXT: "RemoveAllUnusedIncludes1": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: "documentChanges": [
# CHECK-NEXT: {
# CHECK-NEXT: "edits": [
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "RemoveAllUnusedIncludes0",
# CHECK-NEXT: "newText": "",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand All @@ -370,7 +325,6 @@
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "RemoveAllUnusedIncludes1",
# CHECK-NEXT: "newText": "",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand Down Expand Up @@ -398,29 +352,10 @@
# CHECK-NEXT: {
# CHECK-NEXT: "arguments": [
# CHECK-NEXT: {
# CHECK-NEXT: "changeAnnotations": {
# CHECK-NEXT: "AddAllMissingIncludes0": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: },
# CHECK-NEXT: "AddAllMissingIncludes1": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: },
# CHECK-NEXT: "RemoveAllUnusedIncludes0": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: },
# CHECK-NEXT: "RemoveAllUnusedIncludes1": {
# CHECK-NEXT: "label": "",
# CHECK-NEXT: "needsConfirmation": true
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: "documentChanges": [
# CHECK-NEXT: {
# CHECK-NEXT: "edits": [
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "RemoveAllUnusedIncludes0",
# CHECK-NEXT: "newText": "",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand All @@ -434,7 +369,6 @@
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "RemoveAllUnusedIncludes1",
# CHECK-NEXT: "newText": "",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand All @@ -448,7 +382,6 @@
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "AddAllMissingIncludes0",
# CHECK-NEXT: "newText": "#include {{.*}}bar.h{{.*}}",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand All @@ -462,7 +395,6 @@
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "annotationId": "AddAllMissingIncludes1",
# CHECK-NEXT: "newText": "#include {{.*}}foo.h{{.*}}",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
Expand Down
56 changes: 56 additions & 0 deletions clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,62 @@ TEST(DiagnosticTest, MakeUnique) {
"no matching constructor for initialization of 'S'")));
}

TEST(DiagnosticTest, CoroutineInHeader) {
StringRef CoroutineH = R"cpp(
namespace std {
template <class Ret, typename... T>
struct coroutine_traits { using promise_type = typename Ret::promise_type; };
template <class Promise = void>
struct coroutine_handle {
static coroutine_handle from_address(void *) noexcept;
static coroutine_handle from_promise(Promise &promise);
constexpr void* address() const noexcept;
};
template <>
struct coroutine_handle<void> {
template <class PromiseType>
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
static coroutine_handle from_address(void *);
constexpr void* address() const noexcept;
};
struct awaitable {
bool await_ready() noexcept { return false; }
void await_suspend(coroutine_handle<>) noexcept {}
void await_resume() noexcept {}
};
} // namespace std
)cpp";

StringRef Header = R"cpp(
#include "coroutine.h"
template <typename T> struct [[clang::coro_return_type]] Gen {
struct promise_type {
Gen<T> get_return_object() {
return {};
}
std::awaitable initial_suspend();
std::awaitable final_suspend() noexcept;
void unhandled_exception();
void return_value(T t);
};
};
Gen<int> foo_coro(int b) { co_return b; }
)cpp";
Annotations Main(R"cpp(
// error-ok
#include "header.hpp"
Gen<int> $[[bar_coro]](int b) { return foo_coro(b); }
)cpp");
TestTU TU = TestTU::withCode(Main.code());
TU.AdditionalFiles["coroutine.h"] = std::string(CoroutineH);
TU.AdditionalFiles["header.hpp"] = std::string(Header);
TU.ExtraArgs.push_back("--std=c++20");
EXPECT_THAT(TU.build().getDiagnostics(), ElementsAre(hasRange(Main.range())));
}

TEST(DiagnosticTest, MakeShared) {
// We usually miss diagnostics from header functions as we don't parse them.
// std::make_shared is only parsed when --parse-forwarding-functions is set
Expand Down
12 changes: 6 additions & 6 deletions clang-tools-extra/clangd/unittests/FileIndexTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ void update(FileIndex &M, llvm::StringRef Basename, llvm::StringRef Code) {
auto AST = File.build();
M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
AST.getASTContext(), AST.getPreprocessor(),
*AST.getPragmaIncludes());
AST.getPragmaIncludes());
}

TEST(FileIndexTest, CustomizedURIScheme) {
Expand Down Expand Up @@ -254,7 +254,7 @@ TEST(FileIndexTest, IWYUPragmaExport) {
auto AST = File.build();
M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
AST.getASTContext(), AST.getPreprocessor(),
*AST.getPragmaIncludes());
AST.getPragmaIncludes());

auto Symbols = runFuzzyFind(M, "");
EXPECT_THAT(
Expand Down Expand Up @@ -446,7 +446,7 @@ TEST(FileIndexTest, Relations) {
FileIndex Index;
Index.updatePreamble(testPath(TU.Filename), /*Version=*/"null",
AST.getASTContext(), AST.getPreprocessor(),
*AST.getPragmaIncludes());
AST.getPragmaIncludes());
SymbolID A = findSymbol(TU.headerSymbols(), "A").ID;
uint32_t Results = 0;
RelationsRequest Req;
Expand Down Expand Up @@ -567,15 +567,15 @@ TEST(FileIndexTest, StalePreambleSymbolsDeleted) {
auto AST = File.build();
M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
AST.getASTContext(), AST.getPreprocessor(),
*AST.getPragmaIncludes());
AST.getPragmaIncludes());
EXPECT_THAT(runFuzzyFind(M, ""), UnorderedElementsAre(qName("a")));

File.Filename = "f2.cpp";
File.HeaderCode = "int b;";
AST = File.build();
M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
AST.getASTContext(), AST.getPreprocessor(),
*AST.getPragmaIncludes());
AST.getPragmaIncludes());
EXPECT_THAT(runFuzzyFind(M, ""), UnorderedElementsAre(qName("b")));
}

Expand Down Expand Up @@ -720,7 +720,7 @@ TEST(FileIndexTest, Profile) {
auto AST = TestTU::withHeaderCode("int a;").build();
FI.updateMain(FileName, AST);
FI.updatePreamble(FileName, "v1", AST.getASTContext(), AST.getPreprocessor(),
*AST.getPragmaIncludes());
AST.getPragmaIncludes());

llvm::BumpPtrAllocator Alloc;
MemoryTree MT(&Alloc);
Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,10 @@ TEST(IncludeCleaner, IWYUPragmas) {
#include "public.h"
void bar() { foo(); }
#include "keep_main_file.h" // IWYU pragma: keep
)cpp";
TU.AdditionalFiles["behind_keep.h"] = guard("");
TU.AdditionalFiles["keep_main_file.h"] = guard("");
TU.AdditionalFiles["exported.h"] = guard("");
TU.AdditionalFiles["public.h"] = guard("#include \"private.h\"");
TU.AdditionalFiles["private.h"] = guard(R"cpp(
Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clangd/unittests/TestTU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ SymbolSlab TestTU::headerSymbols() const {
auto AST = build();
return std::get<0>(indexHeaderSymbols(
/*Version=*/"null", AST.getASTContext(), AST.getPreprocessor(),
*AST.getPragmaIncludes()));
AST.getPragmaIncludes()));
}

RefSlab TestTU::headerRefs() const {
Expand All @@ -177,7 +177,7 @@ std::unique_ptr<SymbolIndex> TestTU::index() const {
auto Idx = std::make_unique<FileIndex>();
Idx->updatePreamble(testPath(Filename), /*Version=*/"null",
AST.getASTContext(), AST.getPreprocessor(),
*AST.getPragmaIncludes());
AST.getPragmaIncludes());
Idx->updateMain(testPath(Filename), AST);
return std::move(Idx);
}
Expand Down
19 changes: 17 additions & 2 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,12 @@ New checks
Detects C++ code where a reference variable is used to extend the lifetime
of a temporary object that has just been constructed.

- New :doc:`readability-avoid-return-with-void-value
<clang-tidy/checks/readability/avoid-return-with-void-value>` check.

Finds return statements with ``void`` values used within functions with
``void`` result types.

New check aliases
^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -295,6 +301,10 @@ Changes in existing checks
coroutine functions and increase issue detection for cases involving type
aliases with references.

- Improved :doc:`cppcoreguidelines-missing-std-forward
<clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check to
address false positives in the capture list and body of lambdas.

- Improved :doc:`cppcoreguidelines-narrowing-conversions
<clang-tidy/checks/cppcoreguidelines/narrowing-conversions>` check by
extending the `IgnoreConversionFromTypes` option to include types without a
Expand Down Expand Up @@ -358,7 +368,8 @@ Changes in existing checks
<clang-tidy/checks/misc/const-correctness>` check to avoid false positive when
using pointer to member function. Additionally, the check no longer emits
a diagnostic when a variable that is not type-dependent is an operand of a
type-dependent binary operator.
type-dependent binary operator. Improved performance of the check through
optimizations.

- Improved :doc:`misc-include-cleaner
<clang-tidy/checks/misc/include-cleaner>` check by adding option
Expand All @@ -372,7 +383,7 @@ Changes in existing checks

- Improved :doc:`misc-unused-using-decls
<clang-tidy/checks/misc/unused-using-decls>` check to avoid false positive when
using in elaborated type.
using in elaborated type and only check cpp files.

- Improved :doc:`modernize-avoid-bind
<clang-tidy/checks/modernize/avoid-bind>` check to
Expand All @@ -394,6 +405,10 @@ Changes in existing checks
false-positives when constructing the container with ``count`` copies of
elements with value ``value``.

- Improved :doc:`modernize-use-emplace
<clang-tidy/checks/modernize/use-emplace>` to not replace aggregates that
``emplace`` cannot construct with aggregate initialization.

- Improved :doc:`modernize-use-equals-delete
<clang-tidy/checks/modernize/use-equals-delete>` check to ignore
false-positives when special member function is actually used or implicit.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.. title:: clang-tidy - clang-analyzer-optin.core.EnumCastOutOfRange
.. meta::
:http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#optin-core-enumcastoutofrange

clang-analyzer-optin.core.EnumCastOutOfRange
============================================

Check integer to enumeration casts for out of range values.

The `clang-analyzer-optin.core.EnumCastOutOfRange` check is an alias, please see
`Clang Static Analyzer Available Checkers
<https://clang.llvm.org/docs/analyzer/checkers.html#optin-core-enumcastoutofrange>`_
for more information.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.. title:: clang-tidy - clang-analyzer-security.cert.env.InvalidPtr
.. meta::
:http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#security-cert-env-invalidptr

clang-analyzer-security.cert.env.InvalidPtr
===========================================

Finds usages of possibly invalidated pointers.

The `clang-analyzer-security.cert.env.InvalidPtr` check is an alias, please see
`Clang Static Analyzer Available Checkers
<https://clang.llvm.org/docs/analyzer/checkers.html#security-cert-env-invalidptr>`_
for more information.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.. title:: clang-tidy - clang-analyzer-unix.Errno
.. meta::
:http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#unix-errno

clang-analyzer-unix.Errno
=========================

Check for improper use of 'errno'.

The `clang-analyzer-unix.Errno` check is an alias, please see
`Clang Static Analyzer Available Checkers
<https://clang.llvm.org/docs/analyzer/checkers.html#unix-errno>`_
for more information.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.. title:: clang-tidy - clang-analyzer-unix.StdCLibraryFunctions
.. meta::
:http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#unix-stdclibraryfunctions

clang-analyzer-unix.StdCLibraryFunctions
========================================

Check for invalid arguments of C standard library functions, and apply relations
between arguments and return value.

The `clang-analyzer-unix.StdCLibraryFunctions` check is an alias, please see
`Clang Static Analyzer Available Checkers
<https://clang.llvm.org/docs/analyzer/checkers.html#unix-stdclibraryfunctions>`_
for more information.
5 changes: 5 additions & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ Clang-Tidy Checks
:doc:`portability-simd-intrinsics <portability/simd-intrinsics>`,
:doc:`portability-std-allocator-const <portability/std-allocator-const>`,
:doc:`readability-avoid-const-params-in-decls <readability/avoid-const-params-in-decls>`, "Yes"
:doc:`readability-avoid-return-with-void-value <readability/avoid-return-with-void-value>`,
:doc:`readability-avoid-unconditional-preprocessor-if <readability/avoid-unconditional-preprocessor-if>`,
:doc:`readability-braces-around-statements <readability/braces-around-statements>`, "Yes"
:doc:`readability-const-return-type <readability/const-return-type>`, "Yes"
Expand Down Expand Up @@ -440,6 +441,7 @@ Clang-Tidy Checks
:doc:`clang-analyzer-nullability.NullableDereferenced <clang-analyzer/nullability.NullableDereferenced>`, `Clang Static Analyzer nullability.NullableDereferenced <https://clang.llvm.org/docs/analyzer/checkers.html#nullability-nullabledereferenced>`_,
:doc:`clang-analyzer-nullability.NullablePassedToNonnull <clang-analyzer/nullability.NullablePassedToNonnull>`, `Clang Static Analyzer nullability.NullablePassedToNonnull <https://clang.llvm.org/docs/analyzer/checkers.html#nullability-nullablepassedtononnull>`_,
:doc:`clang-analyzer-nullability.NullableReturnedFromNonnull <clang-analyzer/nullability.NullableReturnedFromNonnull>`, `Clang Static Analyzer nullability.NullableReturnedFromNonnull <https://clang.llvm.org/docs/analyzer/checkers.html#nullability-nullablereturnedfromnonnull>`_,
:doc:`clang-analyzer-optin.core.EnumCastOutOfRange <clang-analyzer/optin.core.EnumCastOutOfRange>`, `Clang Static Analyzer optin.core.EnumCastOutOfRange <https://clang.llvm.org/docs/analyzer/checkers.html#optin-core-enumcastoutofrange>`_,
:doc:`clang-analyzer-optin.cplusplus.UninitializedObject <clang-analyzer/optin.cplusplus.UninitializedObject>`, `Clang Static Analyzer optin.cplusplus.UninitializedObject <https://clang.llvm.org/docs/analyzer/checkers.html#optin-cplusplus-uninitializedobject>`_,
:doc:`clang-analyzer-optin.cplusplus.VirtualCall <clang-analyzer/optin.cplusplus.VirtualCall>`, `Clang Static Analyzer optin.cplusplus.VirtualCall <https://clang.llvm.org/docs/analyzer/checkers.html#optin-cplusplus-virtualcall>`_,
:doc:`clang-analyzer-optin.mpi.MPI-Checker <clang-analyzer/optin.mpi.MPI-Checker>`, `Clang Static Analyzer optin.mpi.MPI-Checker <https://clang.llvm.org/docs/analyzer/checkers.html#optin-mpi-mpi-checker>`_,
Expand Down Expand Up @@ -479,6 +481,7 @@ Clang-Tidy Checks
:doc:`clang-analyzer-osx.coreFoundation.containers.OutOfBounds <clang-analyzer/osx.coreFoundation.containers.OutOfBounds>`, `Clang Static Analyzer osx.coreFoundation.containers.OutOfBounds <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-outofbounds>`_,
:doc:`clang-analyzer-osx.coreFoundation.containers.PointerSizedValues <clang-analyzer/osx.coreFoundation.containers.PointerSizedValues>`, `Clang Static Analyzer osx.coreFoundation.containers.PointerSizedValues <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-pointersizedvalues>`_,
:doc:`clang-analyzer-security.FloatLoopCounter <clang-analyzer/security.FloatLoopCounter>`, `Clang Static Analyzer security.FloatLoopCounter <https://clang.llvm.org/docs/analyzer/checkers.html#security-floatloopcounter>`_,
:doc:`clang-analyzer-security.cert.env.InvalidPtr <clang-analyzer/security.cert.env.InvalidPtr>`, `Clang Static Analyzer security.cert.env.InvalidPtr <https://clang.llvm.org/docs/analyzer/checkers.html#security-cert-env-invalidptr>`_,
:doc:`clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling <clang-analyzer/security.insecureAPI.DeprecatedOrUnsafeBufferHandling>`, `Clang Static Analyzer security.insecureAPI.DeprecatedOrUnsafeBufferHandling <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-deprecatedorunsafebufferhandling>`_,
:doc:`clang-analyzer-security.insecureAPI.UncheckedReturn <clang-analyzer/security.insecureAPI.UncheckedReturn>`, `Clang Static Analyzer security.insecureAPI.UncheckedReturn <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-uncheckedreturn>`_,
:doc:`clang-analyzer-security.insecureAPI.bcmp <clang-analyzer/security.insecureAPI.bcmp>`, `Clang Static Analyzer security.insecureAPI.bcmp <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-bcmp>`_,
Expand All @@ -493,9 +496,11 @@ Clang-Tidy Checks
:doc:`clang-analyzer-security.insecureAPI.strcpy <clang-analyzer/security.insecureAPI.strcpy>`, `Clang Static Analyzer security.insecureAPI.strcpy <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-strcpy>`_,
:doc:`clang-analyzer-security.insecureAPI.vfork <clang-analyzer/security.insecureAPI.vfork>`, `Clang Static Analyzer security.insecureAPI.vfork <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-vfork>`_,
:doc:`clang-analyzer-unix.API <clang-analyzer/unix.API>`, `Clang Static Analyzer unix.API <https://clang.llvm.org/docs/analyzer/checkers.html#unix-api>`_,
:doc:`clang-analyzer-unix.Errno <clang-analyzer/unix.Errno>`, `Clang Static Analyzer unix.Errno <https://clang.llvm.org/docs/analyzer/checkers.html#unix-errno>`_,
:doc:`clang-analyzer-unix.Malloc <clang-analyzer/unix.Malloc>`, `Clang Static Analyzer unix.Malloc <https://clang.llvm.org/docs/analyzer/checkers.html#unix-malloc>`_,
:doc:`clang-analyzer-unix.MallocSizeof <clang-analyzer/unix.MallocSizeof>`, `Clang Static Analyzer unix.MallocSizeof <https://clang.llvm.org/docs/analyzer/checkers.html#unix-mallocsizeof>`_,
:doc:`clang-analyzer-unix.MismatchedDeallocator <clang-analyzer/unix.MismatchedDeallocator>`, `Clang Static Analyzer unix.MismatchedDeallocator <https://clang.llvm.org/docs/analyzer/checkers.html#unix-mismatcheddeallocator>`_,
:doc:`clang-analyzer-unix.StdCLibraryFunctions <clang-analyzer/unix.StdCLibraryFunctions>`, `Clang Static Analyzer unix.StdCLibraryFunctions <https://clang.llvm.org/docs/analyzer/checkers.html#unix-stdclibraryfunctions>`_,
:doc:`clang-analyzer-unix.Vfork <clang-analyzer/unix.Vfork>`, `Clang Static Analyzer unix.Vfork <https://clang.llvm.org/docs/analyzer/checkers.html#unix-vfork>`_,
:doc:`clang-analyzer-unix.cstring.BadSizeArg <clang-analyzer/unix.cstring.BadSizeArg>`, `Clang Static Analyzer unix.cstring.BadSizeArg <https://clang.llvm.org/docs/analyzer/checkers.html#unix-cstring-badsizearg>`_,
:doc:`clang-analyzer-unix.cstring.NullArg <clang-analyzer/unix.cstring.NullArg>`, `Clang Static Analyzer unix.cstring.NullArg <https://clang.llvm.org/docs/analyzer/checkers.html#unix-cstring-nullarg>`_,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.. title:: clang-tidy - readability-avoid-return-with-void-value

readability-avoid-return-with-void-value
========================================

Finds return statements with ``void`` values used within functions with
``void`` result types.

A function with a ``void`` return type is intended to perform a task without
producing a return value. Return statements with expressions could lead
to confusion and may miscommunicate the function's intended behavior.

Example:

.. code-block::
void g();
void f() {
// ...
return g();
}
In a long function body, the ``return`` statement suggests that the function
returns a value. However, ``return g();`` is a combination of two statements
that should be written as

.. code-block::
g();
return;
to make clear that ``g()`` is called and immediately afterwards the function
returns (nothing).

In C, the same issue is detected by the compiler if the ``-Wpedantic`` mode
is enabled.

Options
-------

.. option:: IgnoreMacros

The value `false` specifies that return statements expanded
from macros are not checked. The default value is `true`.

.. option:: StrictMode

The value `false` specifies that a direct return statement shall
be excluded from the analysis if it is the only statement not
contained in a block like ``if (cond) return g();``. The default
value is `true`.
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ class PragmaIncludes {
llvm::DenseSet<llvm::sys::fs::UniqueID> ShouldKeep;

/// Owns the strings.
llvm::BumpPtrAllocator Arena;
/// Each record() pushes a new one, while keeping all the old strings alive.
std::vector<std::shared_ptr<const llvm::BumpPtrAllocator>> Arena;

// FIXME: add support for clang use_instead pragma
};
Expand Down
7 changes: 4 additions & 3 deletions clang-tools-extra/include-cleaner/lib/Record.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
: RecordPragma(CI.getPreprocessor(), Out) {}
RecordPragma(const Preprocessor &P, PragmaIncludes *Out)
: SM(P.getSourceManager()), HeaderInfo(P.getHeaderSearchInfo()), Out(Out),
UniqueStrings(Arena) {}
Arena(std::make_shared<llvm::BumpPtrAllocator>()),
UniqueStrings(*Arena) {}

void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
Expand All @@ -204,7 +205,7 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
std::unique(It.getSecond().begin(), It.getSecond().end()),
It.getSecond().end());
}
Out->Arena = std::move(Arena);
Out->Arena.emplace_back(std::move(Arena));
}

void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
Expand Down Expand Up @@ -336,7 +337,7 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
const SourceManager &SM;
const HeaderSearch &HeaderInfo;
PragmaIncludes *Out;
llvm::BumpPtrAllocator Arena;
std::shared_ptr<llvm::BumpPtrAllocator> Arena;
/// Intern table for strings. Contents are on the arena.
llvm::StringSaver UniqueStrings;

Expand Down
58 changes: 31 additions & 27 deletions clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -110,14 +110,16 @@ format::FormatStyle getStyle(llvm::StringRef Filename) {

class Action : public clang::ASTFrontendAction {
public:
Action(llvm::function_ref<bool(llvm::StringRef)> HeaderFilter)
: HeaderFilter(HeaderFilter){};
Action(llvm::function_ref<bool(llvm::StringRef)> HeaderFilter,
llvm::StringMap<std::string> &EditedFiles)
: HeaderFilter(HeaderFilter), EditedFiles(EditedFiles) {}

private:
RecordedAST AST;
RecordedPP PP;
PragmaIncludes PI;
llvm::function_ref<bool(llvm::StringRef)> HeaderFilter;
llvm::StringMap<std::string> &EditedFiles;

bool BeginInvocation(CompilerInstance &CI) override {
// We only perform include-cleaner analysis. So we disable diagnostics that
Expand Down Expand Up @@ -181,17 +183,8 @@ class Action : public clang::ASTFrontendAction {
}
}

if (Edit && (!Results.Missing.empty() || !Results.Unused.empty())) {
if (auto Err = llvm::writeToOutput(
Path, [&](llvm::raw_ostream &OS) -> llvm::Error {
OS << Final;
return llvm::Error::success();
})) {
llvm::errs() << "Failed to apply edits to " << Path << ": "
<< toString(std::move(Err)) << "\n";
++Errors;
}
}
if (!Results.Missing.empty() || !Results.Unused.empty())
EditedFiles.try_emplace(Path, Final);
}

void writeHTML() {
Expand All @@ -215,11 +208,17 @@ class ActionFactory : public tooling::FrontendActionFactory {
: HeaderFilter(HeaderFilter) {}

std::unique_ptr<clang::FrontendAction> create() override {
return std::make_unique<Action>(HeaderFilter);
return std::make_unique<Action>(HeaderFilter, EditedFiles);
}

const llvm::StringMap<std::string> &editedFiles() const {
return EditedFiles;
}

private:
llvm::function_ref<bool(llvm::StringRef)> HeaderFilter;
// Map from file name to final code with the include edits applied.
llvm::StringMap<std::string> EditedFiles;
};

std::function<bool(llvm::StringRef)> headerFilter() {
Expand Down Expand Up @@ -274,21 +273,26 @@ int main(int argc, const char **argv) {

clang::tooling::ClangTool Tool(OptionsParser->getCompilations(),
OptionsParser->getSourcePathList());
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
for (const auto &File : OptionsParser->getSourcePathList()) {
auto Content = llvm::MemoryBuffer::getFile(File);
if (!Content) {
llvm::errs() << "Error: can't read file '" << File
<< "': " << Content.getError().message() << "\n";
return 1;
}
Buffers.push_back(std::move(Content.get()));
Tool.mapVirtualFile(File, Buffers.back()->getBuffer());
}

auto HeaderFilter = headerFilter();
if (!HeaderFilter)
return 1; // error already reported.
ActionFactory Factory(HeaderFilter);
return Tool.run(&Factory) || Errors != 0;
auto ErrorCode = Tool.run(&Factory);
if (Edit) {
for (const auto &NameAndContent : Factory.editedFiles()) {
llvm::StringRef FileName = NameAndContent.first();
const std::string &FinalCode = NameAndContent.second;
if (auto Err = llvm::writeToOutput(
FileName, [&](llvm::raw_ostream &OS) -> llvm::Error {
OS << FinalCode;
return llvm::Error::success();
})) {
llvm::errs() << "Failed to apply edits to " << FileName << ": "
<< toString(std::move(Err)) << "\n";
++Errors;
}
}
}
return ErrorCode || Errors != 0;
}
25 changes: 25 additions & 0 deletions clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,5 +588,30 @@ TEST_F(PragmaIncludeTest, OutlivesFMAndSM) {
EXPECT_THAT(PI.getExporters(Private2FE.get(), FM),
testing::ElementsAre(llvm::cantFail(FM.getFileRef("public.h"))));
}

TEST_F(PragmaIncludeTest, CanRecordManyTimes) {
Inputs.Code = R"cpp(
#include "public.h"
)cpp";
Inputs.ExtraFiles["public.h"] = R"cpp(
#include "private.h"
)cpp";
Inputs.ExtraFiles["private.h"] = R"cpp(
// IWYU pragma: private, include "public.h"
)cpp";

TestAST Processed = build();
auto &FM = Processed.fileManager();
auto PrivateFE = FM.getFile("private.h");
llvm::StringRef Public = PI.getPublic(PrivateFE.get());
EXPECT_EQ(Public, "\"public.h\"");

// This build populates same PI during build, but this time we don't have
// any IWYU pragmas. Make sure strings from previous recordings are still
// alive.
Inputs.Code = "";
build();
EXPECT_EQ(Public, "\"public.h\"");
}
} // namespace
} // namespace clang::include_cleaner
2 changes: 1 addition & 1 deletion clang-tools-extra/test/clang-doc/templates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// RUN: rm -rf %t

template<typename T, int U = 1>
void function<bool, 0>(T x) {}
void function(T x) {}

template<>
void function<bool, 0>(bool x) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ void lambda_value_capture(T&& t) {
}

template <class T>
void lambda_value_reference(T&& t) {
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: forwarding reference parameter 't' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]
[&]() { T other = std::forward<T>(t); };
void lambda_value_capture_copy(T&& t) {
// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: forwarding reference parameter 't' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]
[&,t]() { T other = std::forward<T>(t); };
}

} // namespace positive_cases
Expand Down Expand Up @@ -147,4 +147,29 @@ class AClass {
T data;
};

template <class T>
void lambda_value_reference(T&& t) {
[&]() { T other = std::forward<T>(t); };
}

template<typename T>
void lambda_value_reference_capture_list_ref_1(T&& t) {
[=, &t] { T other = std::forward<T>(t); };
}

template<typename T>
void lambda_value_reference_capture_list_ref_2(T&& t) {
[&t] { T other = std::forward<T>(t); };
}

template<typename T>
void lambda_value_reference_capture_list(T&& t) {
[t = std::forward<T>(t)] { t(); };
}

template <class T>
void lambda_value_reference_auxiliary_var(T&& t) {
[&x = t]() { T other = std::forward<T>(x); };
}

} // namespace negative_cases
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,11 @@ struct NonTrivialWithVector {
std::vector<int> it;
};

struct NonTrivialWithIntAndVector {
int x;
std::vector<int> it;
};

struct NonTrivialWithCtor {
NonTrivialWithCtor();
NonTrivialWithCtor(std::vector<int> const&);
Expand Down Expand Up @@ -1332,6 +1337,14 @@ void testBracedInitTemporaries() {
v3.push_back(NonTrivialWithCtor{{}});
v3.push_back({{0}});
v3.push_back({{}});

std::vector<NonTrivialWithIntAndVector> v4;

// These should not be noticed or fixed; after the correction, the code won't
// compile.
v4.push_back(NonTrivialWithIntAndVector{1, {}});
v4.push_back(NonTrivialWithIntAndVector{});
v4.push_back({});
}

void testWithPointerTypes() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// RUN: %check_clang_tidy %s readability-avoid-return-with-void-value %t
// RUN: %check_clang_tidy -check-suffixes=,INCLUDE-MACROS %s readability-avoid-return-with-void-value %t \
// RUN: -- -config="{CheckOptions: [{key: readability-avoid-return-with-void-value.IgnoreMacros, value: false}]}" \
// RUN: --
// RUN: %check_clang_tidy -check-suffixes=LENIENT %s readability-avoid-return-with-void-value %t \
// RUN: -- -config="{CheckOptions: [{key: readability-avoid-return-with-void-value.StrictMode, value: false}]}" \
// RUN: --

void f1();

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]
}

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]
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]
}

template<class T>
T f4() {}

void f5() {
return f4<void>();
// 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]
}

void f6() { return; }

int f7() { return 1; }

int f8() { return f7(); }

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]
}

#define RETURN_VOID return (void)1

void f10() {
RETURN_VOID;
// 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 <typename A>
struct C {
C(A) {}
};

template <class T>
C<T> f11() { return {}; }

using VOID = void;

VOID f12();

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]
}
6 changes: 6 additions & 0 deletions clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ set(C_INCLUDE_DIRS "" CACHE STRING
set(GCC_INSTALL_PREFIX "" CACHE PATH "Directory where gcc is installed." )
set(DEFAULT_SYSROOT "" CACHE STRING
"Default <path> to all compiler invocations for --sysroot=<path>." )
if(GCC_INSTALL_PREFIX)
message(WARNING "GCC_INSTALL_PREFIX is deprecated and will be removed. Use "
"configuration files (https://clang.llvm.org/docs/UsersManual.html#configuration-files)"
"to specify the default --gcc-install-dir= or --gcc-triple=. --gcc-toolchain= is discouraged. "
"See https://github.com/llvm/llvm-project/pull/77537 for detail.")
endif()

set(ENABLE_LINKER_BUILD_ID OFF CACHE BOOL "pass --build-id to ld")

Expand Down
41 changes: 41 additions & 0 deletions clang/cmake/caches/Release.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Plain options configure the first build.
# BOOTSTRAP_* options configure the second build.
# BOOTSTRAP_BOOTSTRAP_* options configure the third build.

set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")

# Stage 1 Bootstrap Setup
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
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 "")

# Stage 1 Options
set(LLVM_ENABLE_PROJECTS "clang" 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
check-all
check-llvm
check-clang CACHE STRING "")

# Stage 2 Options
set(BOOTSTRAP_LLVM_ENABLE_PROJECTS "clang" CACHE STRING "")
set(BOOTSTRAP_LLVM_TARGETS_TO_BUILD Native CACHE 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 "")
6 changes: 5 additions & 1 deletion clang/docs/ClangFormat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ An easy way to create the ``.clang-format`` file is:
Available style options are described in :doc:`ClangFormatStyleOptions`.

.clang-format-ignore
====================

You can create ``.clang-format-ignore`` files to make ``clang-format`` ignore
certain files. A ``.clang-format-ignore`` file consists of patterns of file path
names. It has the following format:
Expand All @@ -141,7 +144,8 @@ names. It has the following format:
* A non-comment line is a single pattern.
* The slash (``/``) is used as the directory separator.
* A pattern is relative to the directory of the ``.clang-format-ignore`` file
(or the root directory if the pattern starts with a slash).
(or the root directory if the pattern starts with a slash). Patterns
containing drive names (e.g. ``C:``) are not supported.
* Patterns follow the rules specified in `POSIX 2.13.1, 2.13.2, and Rule 1 of
2.13.3 <https://pubs.opengroup.org/onlinepubs/9699919799/utilities/
V3_chap02.html#tag_18_13>`_.
Expand Down
321 changes: 321 additions & 0 deletions clang/docs/HLSL/FunctionCalls.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,321 @@
===================
HLSL Function Calls
===================

.. contents::
:local:

Introduction
============

This document describes the design and implementation of HLSL's function call
semantics in Clang. This includes details related to argument conversion and
parameter lifetimes.

This document does not seek to serve as official documentation for HLSL's
call semantics, but does provide an overview to assist a reader. The
authoritative documentation for HLSL's language semantics is the `draft language
specification <https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf>`_.

Argument Semantics
==================

In HLSL, all function arguments are passed by value in and out of functions.
HLSL has 3 keywords which denote the parameter semantics (``in``, ``out`` and
``inout``). In a function declaration a parameter may be annotated any of the
following ways:

#. <no parameter annotation> - denotes input
#. ``in`` - denotes input
#. ``out`` - denotes output
#. ``in out`` - denotes input and output
#. ``out in`` - denotes input and output
#. ``inout`` - denotes input and output

Parameters that are exclusively input behave like C/C++ parameters that are
passed by value.

For parameters that are output (or input and output), a temporary value is
created in the caller. The temporary value is then passed by-address. For
output-only parameters, the temporary is uninitialized when passed (if the
parameter is not explicitly initialized inside the function an undefined value
is stored back to the argument expression). For parameters that are both input
and output, the temporary is initialized from the lvalue argument expression
through implicit or explicit casting from the lvalue argument type to the
parameter type.

On return of the function, the values of any parameter temporaries are written
back to the argument expression through an inverted conversion sequence (if an
``out`` parameter was not initialized in the function, the uninitialized value
may be written back).

Parameters of constant-sized array type are also passed with value semantics.
This requires input parameters of arrays to construct temporaries and the
temporaries go through array-to-pointer decay when initializing parameters.

Implementations are allowed to avoid unnecessary temporaries, and HLSL's strict
no-alias rules can enable some trivial optimizations.

Array Temporaries
-----------------

Given the following example:

.. code-block:: c++

void fn(float a[4]) {
a[0] = a[1] + a[2] + a[3];
}

float4 main() : SV_Target {
float arr[4] = {1, 1, 1, 1};
fn(arr);
return float4(arr[0], arr[1], arr[2], arr[3]);
}

In C or C++, the array parameter decays to a pointer, so after the call to
``fn``, the value of ``arr[0]`` is ``3``. In HLSL, the array is passed by value,
so modifications inside ``fn`` do not propagate out.

.. note::

DXC may pass unsized arrays directly as decayed pointers, which is an
unfortunate behavior divergence.

Out Parameter Temporaries
-------------------------

.. code-block:: c++

void Init(inout int X, inout int Y) {
Y = 2;
X = 1;
}

void main() {
int V;
Init(V, V); // MSVC (or clang-cl) V == 2, Clang V == 1
}

In the above example the ``Init`` function's behavior depends on the C++
implementation. C++ does not define the order in which parameters are
initialized or destroyed. In MSVC and Clang's MSVC compatibility mode, arguments
are emitted right-to-left and destroyed left-to-right. This means that the
parameter initialization and destruction occurs in the order: {``Y``, ``X``,
``~X``, ``~Y``}. This causes the write-back of the value of ``Y`` to occur last,
so the resulting value of ``V`` is ``2``. In the Itanium C++ ABI, the parameter
ordering is reversed, so the initialization and destruction occurs in the order:
{``X``, ``Y``, ``~Y``, ``X``}. This causes the write-back of the value ``X`` to
occur last, resulting in the value of ``V`` being set to ``1``.

.. code-block:: c++

void Trunc(inout int3 V) { }


void main() {
float3 F = {1.5, 2.6, 3.3};
Trunc(F); // F == {1.0, 2.0, 3.0}
}

In the above example, the argument expression ``F`` undergoes element-wise
conversion from a float vector to an integer vector to create a temporary
``int3``. On expiration the temporary undergoes elementwise conversion back to
the floating point vector type ``float3``. This results in an implicit
element-wise conversion of the vector even if the value is unused in the
function (effectively truncating the floating point values).


.. code-block:: c++

void UB(out int X) {}

void main() {
int X = 7;
UB(X); // X is undefined!
}

In this example an initialized value is passed to an ``out`` parameter.
Parameters marked ``out`` are not initialized by the argument expression or
implicitly by the function. They must be explicitly initialized. In this case
the argument is not initialized in the function so the temporary is still
uninitialized when it is copied back to the argument expression. This is
undefined behavior in HLSL, and any use of the argument after the call is a use
of an undefined value which may be illegal in the target (DXIL programs with
used or potentially used ``undef`` or ``poison`` values fail validation).

Clang Implementation
====================

.. note::

The implementation described here is a proposal. It has not yet been fully
implemented, so the current state of Clang's sources may not reflect this
design. A prototype implementation was built on DXC which is Clang-3.7 based.
The prototype can be found
`here <https://github.com/microsoft/DirectXShaderCompiler/pull/5249>`_. A lot
of the changes in the prototype implementation are restoring Clang-3.7 code
that was previously modified to its original state.

The implementation in clang depends on two new AST nodes and minor extensions to
Clang's existing support for Objective-C write-back arguments. The goal of this
design is to capture the semantic details of HLSL function calls in the AST, and
minimize the amount of magic that needs to occur during IR generation.

The two new AST nodes are ``HLSLArrayTemporaryExpr`` and ``HLSLOutParamExpr``,
which respectively represent the temporaries used for passing arrays by value
and the temporaries created for function outputs.

Array Temporaries
-----------------

The ``HLSLArrayTemporaryExpr`` represents temporary values for input
constant-sized array arguments. This applies for all constant-sized array
arguments regardless of whether or not the parameter is constant-sized or
unsized.

.. code-block:: c++

void SizedArray(float a[4]);
void UnsizedArray(float a[]);

void main() {
float arr[4] = {1, 1, 1, 1};
SizedArray(arr);
UnsizedArray(arr);
}

In the example above, the following AST is generated for the call to
``SizedArray``:

.. code-block:: text
CallExpr 'void'
|-ImplicitCastExpr 'void (*)(float [4])' <FunctionToPointerDecay>
| `-DeclRefExpr 'void (float [4])' lvalue Function 'SizedArray' 'void (float [4])'
`-HLSLArrayTemporaryExpr 'float [4]'
`-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]'
In the example above, the following AST is generated for the call to
``UnsizedArray``:

.. code-block:: text
CallExpr 'void'
|-ImplicitCastExpr 'void (*)(float [])' <FunctionToPointerDecay>
| `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])'
`-HLSLArrayTemporaryExpr 'float [4]'
`-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]'
In both of these cases the argument expression is of known array size so we can
initialize an appropriately sized temporary.

It is illegal in HLSL to convert an unsized array to a sized array:

.. code-block:: c++

void SizedArray(float a[4]);
void UnsizedArray(float a[]) {
SizedArray(a); // Cannot convert float[] to float[4]
}

When converting a sized array to an unsized array, an array temporary can also
be inserted. Given the following code:

.. code-block:: c++

void UnsizedArray(float a[]);
void SizedArray(float a[4]) {
UnsizedArray(a);
}

An expected AST should be something like:

.. code-block:: text
CallExpr 'void'
|-ImplicitCastExpr 'void (*)(float [])' <FunctionToPointerDecay>
| `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])'
`-HLSLArrayTemporaryExpr 'float [4]'
`-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]'
Out Parameter Temporaries
-------------------------

Output parameters are defined in HLSL as *casting expiring values* (cx-values),
which is a term made up for HLSL. A cx-value is a temporary value which may be
the result of a cast, and stores its value back to an lvalue when the value
expires.

To represent this concept in Clang we introduce a new ``HLSLOutParamExpr``. An
``HLSLOutParamExpr`` has two forms, one with a single sub-expression and one
with two sub-expressions.

The single sub-expression form is used when the argument expression and the
function parameter are the same type, so no cast is required. As in this
example:

.. code-block:: c++

void Init(inout int X) {
X = 1;
}

void main() {
int V;
Init(V);
}

The expected AST formulation for this code would be something like:

.. code-block:: text
CallExpr 'void'
|-ImplicitCastExpr 'void (*)(int &)' <FunctionToPointerDecay>
| `-DeclRefExpr 'void (int &)' lvalue Function 'Init' 'void (int &)'
|-HLSLOutParamExpr 'int' lvalue inout
`-DeclRefExpr 'int' lvalue Var 'V' 'int'
The ``HLSLOutParamExpr`` captures that the value is ``inout`` vs ``out`` to
denote whether or not the temporary is initialized from the sub-expression. If
no casting is required the sub-expression denotes the lvalue expression that the
cx-value will be copied to when the value expires.

The two sub-expression form of the AST node is required when the argument type
is not the same as the parameter type. Given this example:

.. code-block:: c++

void Trunc(inout int3 V) { }


void main() {
float3 F = {1.5, 2.6, 3.3};
Trunc(F);
}

For this case the ``HLSLOutParamExpr`` will have sub-expressions to record both
casting expression sequences for the initialization and write back:

.. code-block:: text
-CallExpr 'void'
|-ImplicitCastExpr 'void (*)(int3 &)' <FunctionToPointerDecay>
| `-DeclRefExpr 'void (int3 &)' lvalue Function 'inc_i32' 'void (int3 &)'
`-HLSLOutParamExpr 'int3' lvalue inout
|-ImplicitCastExpr 'float3' <IntegralToFloating>
| `-ImplicitCastExpr 'int3' <LValueToRValue>
| `-OpaqueValueExpr 'int3' lvalue
`-ImplicitCastExpr 'int3' <FloatingToIntegral>
`-ImplicitCastExpr 'float3' <LValueToRValue>
`-DeclRefExpr 'float3' lvalue 'F' 'float3'
In this formation the write-back casts are captured as the first sub-expression
and they cast from an ``OpaqueValueExpr``. In IR generation we can use the
``OpaqueValueExpr`` as a placeholder for the ``HLSLOutParamExpr``'s temporary
value on function return.

In code generation this can be implemented with some targeted extensions to the
Objective-C write-back support. Specifically extending CGCall.cpp's
``EmitWriteback`` function to support casting expressions and emission of
aggregate lvalues.
1 change: 1 addition & 0 deletions clang/docs/HLSL/HLSLDocs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ HLSL Design and Implementation
HLSLIRReference
ResourceTypes
EntryFunctions
FunctionCalls
34 changes: 32 additions & 2 deletions clang/docs/InternalsManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3364,7 +3364,7 @@ Multiple occurrences accumulate prefixes. For example,

Specifying Diagnostics
^^^^^^^^^^^^^^^^^^^^^^
Indicating that a line expects an error or a warning is simple. Put a comment
Indicating that a line expects an error or a warning is easy. Put a comment
on the line that has the diagnostic, use
``expected-{error,warning,remark,note}`` to tag if it's an expected error,
warning, remark, or note (respectively), and place the expected text between
Expand All @@ -3373,6 +3373,9 @@ enough to ensure that the correct diagnostic was emitted. (Note: full text
should be included in test cases unless there is a compelling reason to use
truncated text instead.)

For a full description of the matching behavior, including more complex
matching scenarios, see :ref:`matching <DiagnosticMatching>` below.

Here's an example of the most commonly used way to specify expected
diagnostics:

Expand Down Expand Up @@ -3458,8 +3461,33 @@ A range can also be specified by ``<n>-<m>``. For example:

In this example, the diagnostic may appear only once, if at all.

.. _DiagnosticMatching:

Matching Modes
~~~~~~~~~~~~~~

The default matching mode is simple string, which looks for the expected text
that appears between the first `{{` and `}}` pair of the comment. The string is
interpreted just as-is, with one exception: the sequence `\n` is converted to a
single newline character. This mode matches the emitted diagnostic when the
text appears as a substring at any position of the emitted message.

To enable matching against desired strings that contain `}}` or `{{`, the
string-mode parser accepts opening delimiters of more than two curly braces,
like `{{{`. It then looks for a closing delimiter of equal "width" (i.e `}}}`).
For example:

.. code-block:: c++

// expected-note {{{evaluates to '{{2, 3, 4}} == {0, 3, 4}'}}}

The intent is to allow the delimeter to be wider than the longest `{` or `}`
brace sequence in the content, so that if your expected text contains `{{{`
(three braces) it may be delimited with `{{{{` (four braces), and so on.

Regex matching mode may be selected by appending ``-re`` to the diagnostic type
and including regexes wrapped in double curly braces in the directive, such as:
and including regexes wrapped in double curly braces (`{{` and `}}`) in the
directive, such as:

.. code-block:: text
Expand All @@ -3471,6 +3499,8 @@ Examples matching error: "variable has incomplete type 'struct s'"

// expected-error {{variable has incomplete type 'struct s'}}
// expected-error {{variable has incomplete type}}
// expected-error {{{variable has incomplete type}}}
// expected-error {{{{variable has incomplete type}}}}

// expected-error-re {{variable has type 'struct {{.}}'}}
// expected-error-re {{variable has type 'struct {{.*}}'}}
Expand Down
77 changes: 67 additions & 10 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ These changes are ones which we think may surprise users when upgrading to
Clang |release| because of the opportunity they pose for disruption to existing
code bases.

- The CMake variable ``GCC_INSTALL_PREFIX`` (which sets the default
``--gcc-toolchain=``) is deprecated and will be removed. Specify
``--gcc-install-dir=`` or ``--gcc-triple=`` in a `configuration file
<https://clang.llvm.org/docs/UsersManual.html#configuration-files>` as a
replacement.
(`#77537 <https://github.com/llvm/llvm-project/pull/77537>`_)

C/C++ Language Potentially Breaking Changes
-------------------------------------------
Expand Down Expand Up @@ -357,6 +363,7 @@ Attribute Changes in Clang
- Clang now introduced ``[[clang::coro_lifetimebound]]`` attribute.
All parameters of a function are considered to be lifetime bound if the function
returns a type annotated with ``[[clang::coro_lifetimebound]]`` and ``[[clang::coro_return_type]]``.
This analysis can be disabled for a function by annotating the function with ``[[clang::coro_disable_lifetimebound]]``.

Improvements to Clang's diagnostics
-----------------------------------
Expand Down Expand Up @@ -518,6 +525,9 @@ Improvements to Clang's diagnostics
- Clang now diagnoses definitions of friend function specializations, e.g. ``friend void f<>(int) {}``.
- Clang now diagnoses narrowing conversions involving const references.
(`#63151: <https://github.com/llvm/llvm-project/issues/63151>`_).
- Clang now diagnoses unexpanded packs within the template argument lists of function template specializations.
- Clang now diagnoses attempts to bind a bitfield to an NTTP of a reference type as erroneous
converted constant expression and not as a reference to subobject.


Improvements to Clang's time-trace
Expand Down Expand Up @@ -607,7 +617,9 @@ Bug Fixes in This Version
- Clang will correctly evaluate ``noexcept`` expression for template functions
of template classes. Fixes
(`#68543 <https://github.com/llvm/llvm-project/issues/68543>`_,
`#42496 <https://github.com/llvm/llvm-project/issues/42496>`_)
`#42496 <https://github.com/llvm/llvm-project/issues/42496>`_,
`#77071 <https://github.com/llvm/llvm-project/issues/77071>`_,
`#77411 <https://github.com/llvm/llvm-project/issues/77411>`_)
- Fixed an issue when a shift count larger than ``__INT64_MAX__``, in a right
shift operation, could result in missing warnings about
``shift count >= width of type`` or internal compiler error.
Expand Down Expand Up @@ -685,9 +697,23 @@ Bug Fixes in This Version
(`#65568 <https://github.com/llvm/llvm-project/issues/65568>`_)
- Fix an issue where clang doesn't respect detault template arguments that
are added in a later redeclaration for CTAD.
Fixes (#69987 <https://github.com/llvm/llvm-project/issues/69987>`_)
Fixes (`#69987 <https://github.com/llvm/llvm-project/issues/69987>`_)
- Fix an issue where CTAD fails for explicit type conversion.
Fixes (#64347 <https://github.com/llvm/llvm-project/issues/64347>`_)
Fixes (`#64347 <https://github.com/llvm/llvm-project/issues/64347>`_)
- Fix crash when using C++ only tokens like ``::`` in C compiler clang.
Fixes (`#73559 <https://github.com/llvm/llvm-project/issues/73559>`_)
- Clang now accepts recursive non-dependent calls to functions with deduced
return type.
Fixes (`#71015 <https://github.com/llvm/llvm-project/issues/71015>`_)
- Fix assertion failure when initializing union containing struct with
flexible array member using empty initializer list.
Fixes (`#77085 <https://github.com/llvm/llvm-project/issues/77085>`_)
- Fix assertion crash due to failed scope restoring caused by too-early VarDecl
invalidation by invalid initializer Expr.
Fixes (`#30908 <https://github.com/llvm/llvm-project/issues/30908>`_)
- Clang now emits correct source location for code-coverage regions in `if constexpr`
and `if consteval` branches.
Fixes (`#54419 <https://github.com/llvm/llvm-project/issues/54419>`_)


Bug Fixes to Compiler Builtins
Expand Down Expand Up @@ -716,7 +742,8 @@ Bug Fixes to C++ Support

- Clang emits an error on substitution failure within lambda body inside a
requires-expression. This fixes:
(`#64138 <https://github.com/llvm/llvm-project/issues/64138>`_).
(`#64138 <https://github.com/llvm/llvm-project/issues/64138>`_) and
(`#71684 <https://github.com/llvm/llvm-project/issues/71684>`_).

- Update ``FunctionDeclBitfields.NumFunctionDeclBits``. This fixes:
(`#64171 <https://github.com/llvm/llvm-project/issues/64171>`_).
Expand Down Expand Up @@ -843,6 +870,16 @@ Bug Fixes to C++ Support
- Fix crash when parsing nested requirement. Fixes:
(`#73112 <https://github.com/llvm/llvm-project/issues/73112>`_)

- Fixed a crash caused by using return type requirement in a lambda. Fixes:
(`#63808 <https://github.com/llvm/llvm-project/issues/63808>`_)
(`#64607 <https://github.com/llvm/llvm-project/issues/64607>`_)
(`#64086 <https://github.com/llvm/llvm-project/issues/64086>`_)

- Fixed a regression where clang forgets how to substitute into constraints on template-template
parameters. Fixes:
(`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and
(`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an import failure of recursive friend class template.
Expand All @@ -856,6 +893,12 @@ Bug Fixes to AST Handling
- Fixed a bug where RecursiveASTVisitor fails to visit the
initializer of a bitfield.
`Issue 64916 <https://github.com/llvm/llvm-project/issues/64916>`_
- Fixed a bug where range-loop-analysis checks for trivial copyability,
rather than trivial copy-constructibility
`Issue 47355 <https://github.com/llvm/llvm-project/issues/47355>`_
- Fixed a bug where Template Instantiation failed to handle Lambda Expressions
with certain types of Attributes.
(`#76521 <https://github.com/llvm/llvm-project/issues/76521>`_)

Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -910,6 +953,15 @@ X86 Support
* Support intrinsic of ``_uwrmsr``.
- Support ISA of ``AVX10.1``.
- ``-march=pantherlake`` and ``-march=clearwaterforest`` are now supported.
- Added ABI handling for ``__float128`` to match with GCC.
- Emit warnings for options to enable knl/knm specific ISAs: AVX512PF, AVX512ER
and PREFETCHWT1. From next version (LLVM 19), these ISAs' intrinsic supports
will be deprecated:
* intrinsic series of *_exp2a23_*
* intrinsic series of *_rsqrt28_*
* intrinsic series of *_rcp28_*
* intrinsic series of *_prefetch_i[3|6][2|4]gather_*
* intrinsic series of *_prefetch_i[3|6][2|4]scatter_*

Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -1127,9 +1179,11 @@ Improvements
^^^^^^^^^^^^

- Improved the ``unix.StdCLibraryFunctions`` checker by modeling more
functions like ``send``, ``recv``, ``readlink``, ``fflush`` and
``errno`` behavior.
functions like ``send``, ``recv``, ``readlink``, ``fflush``, ``mkdtemp``,
``getcwd`` and ``errno`` behavior.
(`52ac71f92d38 <https://github.com/llvm/llvm-project/commit/52ac71f92d38f75df5cb88e9c090ac5fd5a71548>`_,
`#77040 <https://github.com/llvm/llvm-project/pull/77040>`_,
`#76671 <https://github.com/llvm/llvm-project/pull/76671>`_,
`#71373 <https://github.com/llvm/llvm-project/pull/71373>`_,
`#76557 <https://github.com/llvm/llvm-project/pull/76557>`_,
`#71392 <https://github.com/llvm/llvm-project/pull/71392>`_)
Expand Down Expand Up @@ -1157,15 +1211,18 @@ Improvements
(`c3a87ddad62a <https://github.com/llvm/llvm-project/commit/c3a87ddad62a6cc01acaccc76592bc6730c8ac3c>`_,
`0954dc3fb921 <https://github.com/llvm/llvm-project/commit/0954dc3fb9214b994623f5306473de075f8e3593>`_)

- Improved the ``alpha.unix.Stream`` checker by modeling more functions like,
``fflush``, ``fputs``, ``fgetc``, ``fputc``, ``fopen``, ``fopen``, ``fgets``.
(`#74296 <https://github.com/llvm/llvm-project/pull/74296>`_,
- Improved the ``alpha.unix.Stream`` checker by modeling more functions
``fputs``, ``fputc``, ``fgets``, ``fgetc``, ``fdopen``, ``ungetc``, ``fflush``
and no not recognize alternative ``fopen`` and ``tmpfile`` implementations.
(`#76776 <https://github.com/llvm/llvm-project/pull/76776>`_,
`#74296 <https://github.com/llvm/llvm-project/pull/74296>`_,
`#73335 <https://github.com/llvm/llvm-project/pull/73335>`_,
`#72627 <https://github.com/llvm/llvm-project/pull/72627>`_,
`#71518 <https://github.com/llvm/llvm-project/pull/71518>`_,
`#72016 <https://github.com/llvm/llvm-project/pull/72016>`_,
`#70540 <https://github.com/llvm/llvm-project/pull/70540>`_,
`#73638 <https://github.com/llvm/llvm-project/pull/73638>`_)
`#73638 <https://github.com/llvm/llvm-project/pull/73638>`_,
`#77331 <https://github.com/llvm/llvm-project/pull/77331>`_)

- The ``alpha.security.taint.TaintPropagation`` checker no longer propagates
taint on ``strlen`` and ``strnlen`` calls, unless these are marked
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/Frontend/HLSL/HLSLResource.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/raw_ostream.h"
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,9 @@ class CXXRecordDecl : public RecordDecl {
/// (C++11 [class]p6).
bool isTriviallyCopyable() const;

/// Determine whether this class is considered trivially copyable per
bool isTriviallyCopyConstructible() const;

/// Determine whether this class is considered trivial.
///
/// C++11 [class]p6:
Expand Down Expand Up @@ -2044,6 +2047,14 @@ class RequiresExprBodyDecl : public Decl, public DeclContext {
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == RequiresExprBody; }

static DeclContext *castToDeclContext(const RequiresExprBodyDecl *D) {
return static_cast<DeclContext *>(const_cast<RequiresExprBodyDecl *>(D));
}

static RequiresExprBodyDecl *castFromDeclContext(const DeclContext *DC) {
return static_cast<RequiresExprBodyDecl *>(const_cast<DeclContext *>(DC));
}
};

/// Represents a static or instance method of a struct/union/class.
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -1631,8 +1631,10 @@ class CompoundStmt final
SourceLocation RB);

// Build an empty compound statement with a location.
explicit CompoundStmt(SourceLocation Loc)
: Stmt(CompoundStmtClass), LBraceLoc(Loc), RBraceLoc(Loc) {
explicit CompoundStmt(SourceLocation Loc) : CompoundStmt(Loc, Loc) {}

CompoundStmt(SourceLocation Loc, SourceLocation EndLoc)
: Stmt(CompoundStmtClass), LBraceLoc(Loc), RBraceLoc(EndLoc) {
CompoundStmtBits.NumStmts = 0;
CompoundStmtBits.HasFPFeatures = 0;
}
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/TextNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ class TextNodeDumper
void VisitGotoStmt(const GotoStmt *Node);
void VisitCaseStmt(const CaseStmt *Node);
void VisitReturnStmt(const ReturnStmt *Node);
void VisitCoawaitExpr(const CoawaitExpr *Node);
void VisitCoreturnStmt(const CoreturnStmt *Node);
void VisitCompoundStmt(const CompoundStmt *Node);
void VisitConstantExpr(const ConstantExpr *Node);
void VisitCallExpr(const CallExpr *Node);
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,9 @@ class QualType {
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
bool isTriviallyCopyableType(const ASTContext &Context) const;

/// Return true if this is a trivially copyable type
bool isTriviallyCopyConstructibleType(const ASTContext &Context) const;

/// Return true if this is a trivially relocatable type.
bool isTriviallyRelocatableType(const ASTContext &Context) const;

Expand Down Expand Up @@ -4224,6 +4227,8 @@ class FunctionProtoType final
ExceptionSpecInfo() = default;

ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {}

void instantiate();
};

/// Extra information about a function prototype. ExtProtoInfo is not
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class UnsafeBufferUsageHandler {

/// Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeOperation(const Stmt *Operation,
bool IsRelatedToDecl) = 0;
bool IsRelatedToDecl, ASTContext &Ctx) = 0;

/// Invoked when a fix is suggested against a variable. This function groups
/// all variables that must be fixed together (i.e their types must be changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ WARNING_GADGET(Decrement)
WARNING_GADGET(ArraySubscript)
WARNING_GADGET(PointerArithmetic)
WARNING_GADGET(UnsafeBufferUsageAttr)
WARNING_GADGET(DataInvocation)
FIXABLE_GADGET(ULCArraySubscript) // `DRE[any]` in an Unspecified Lvalue Context
FIXABLE_GADGET(DerefSimplePtrArithFixable)
FIXABLE_GADGET(PointerDereference)
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Analysis/CFG.h
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,9 @@ class CFG {
//===--------------------------------------------------------------------===//

class BuildOptions {
std::bitset<Stmt::lastStmtConstant> alwaysAddMask;
// Stmt::lastStmtConstant has the same value as the last Stmt kind,
// so make sure we add one to account for this!
std::bitset<Stmt::lastStmtConstant + 1> alwaysAddMask;

public:
using ForcedBlkExprs = llvm::DenseMap<const Stmt *, const CFGBlock *>;
Expand Down
23 changes: 23 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ def ExternalGlobalVar : SubsetSubject<Var,
!S->isLocalExternDecl()}],
"external global variables">;

def NonTLSGlobalVar : SubsetSubject<Var,
[{S->hasGlobalStorage() &&
S->getTLSKind() == 0}],
"non-TLS global variables">;

def InlineFunction : SubsetSubject<Function,
[{S->isInlineSpecified()}], "inline functions">;

Expand Down Expand Up @@ -431,6 +436,7 @@ def TargetAArch64 : TargetArch<["aarch64", "aarch64_be", "aarch64_32"]>;
def TargetAnyArm : TargetArch<!listconcat(TargetARM.Arches, TargetAArch64.Arches)>;
def TargetAVR : TargetArch<["avr"]>;
def TargetBPF : TargetArch<["bpfel", "bpfeb"]>;
def TargetLoongArch : TargetArch<["loongarch32", "loongarch64"]>;
def TargetMips32 : TargetArch<["mips", "mipsel"]>;
def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>;
def TargetMSP430 : TargetArch<["msp430"]>;
Expand Down Expand Up @@ -1121,6 +1127,14 @@ def CoroLifetimeBound : InheritableAttr {
let SimpleHandler = 1;
}

def CoroDisableLifetimeBound : InheritableAttr {
let Spellings = [Clang<"coro_disable_lifetimebound">];
let Subjects = SubjectList<[Function]>;
let LangOpts = [CPlusPlus];
let Documentation = [CoroLifetimeBoundDoc];
let SimpleHandler = 1;
}

// OSObject-based attributes.
def OSConsumed : InheritableParamAttr {
let Spellings = [Clang<"os_consumed">];
Expand Down Expand Up @@ -2730,6 +2744,15 @@ def PragmaClangTextSection : InheritableAttr {
let Documentation = [InternalOnly];
}

def CodeModel : InheritableAttr, TargetSpecificAttr<TargetLoongArch> {
let Spellings = [GCC<"model">];
let Args = [EnumArgument<"Model", "llvm::CodeModel::Model",
["normal", "medium", "extreme"], ["Small", "Medium", "Large"],
/*opt=*/0, /*fake=*/0, /*isExternalType=*/1>];
let Subjects = SubjectList<[NonTLSGlobalVar], ErrorDiag>;
let Documentation = [CodeModelDocs];
}

def Sentinel : InheritableAttr {
let Spellings = [GCC<"sentinel">];
let Args = [DefaultIntArgument<"Sentinel", 0>,
Expand Down
35 changes: 31 additions & 4 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ global variable or function should be in after translation.
let Heading = "section, __declspec(allocate)";
}

def CodeModelDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
The ``model`` attribute allows overriding the translation unit's
code model (specified by ``-mcmodel``) for a specific global variable.
}];
let Heading = "model";
}

def UsedDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down Expand Up @@ -7671,9 +7680,12 @@ The ``[[clang::coro_lifetimebound]]`` is a class attribute which can be applied
to a coroutine return type (`CRT`_) (i.e.
it should also be annotated with ``[[clang::coro_return_type]]``).

All parameters of a function are considered to be lifetime bound. See `documentation`_
of ``[[clang::lifetimebound]]`` for more details.
if the function returns a coroutine return type (CRT) annotated with ``[[clang::coro_lifetimebound]]``.
All parameters of a function are considered to be lifetime bound if the function returns a
coroutine return type (CRT) annotated with ``[[clang::coro_lifetimebound]]``.
This lifetime bound analysis can be disabled for a coroutine wrapper or a coroutine by annotating the function
with ``[[clang::coro_disable_lifetimebound]]`` function attribute .
See `documentation`_ of ``[[clang::lifetimebound]]`` for details about lifetime bound analysis.


Reference parameters of a coroutine are susceptible to capturing references to temporaries or local variables.

Expand Down Expand Up @@ -7703,7 +7715,7 @@ Both coroutines and coroutine wrappers are part of this analysis.
};

Task<int> coro(const int& a) { co_return a + 1; }
Task<int> [[clang::coro_wrapper]] coro_wrapper(const int& a, const int& b) {
[[clang::coro_wrapper]] Task<int> coro_wrapper(const int& a, const int& b) {
return a > b ? coro(a) : coro(b);
}
Task<int> temporary_reference() {
Expand All @@ -7718,6 +7730,21 @@ Both coroutines and coroutine wrappers are part of this analysis.
return coro(a); // warning: returning address of stack variable `a`.
}

This analysis can be disabled for all calls to a particular function by annotating the function
with function attribute ``[[clang::coro_disable_lifetimebound]]``.
For example, this could be useful for coroutine wrappers which accept reference parameters
but do not pass them to the underlying coroutine or pass them by value.

.. code-block:: c++

Task<int> coro(int a) { co_return a + 1; }
[[clang::coro_wrapper, clang::coro_disable_lifetimebound]] Task<int> coro_wrapper(const int& a) {
return coro(a + 1);
}
void use() {
auto task = coro_wrapper(1); // use of temporary is fine as the argument is not lifetime bound.
}

.. _`documentation`: https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
.. _`CRT`: https://clang.llvm.org/docs/AttributeReference.html#coro-return-type
}];
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/BuiltinsAArch64.def
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ TARGET_BUILTIN(__builtin_arm_ldg, "v*v*", "t", "mte")
TARGET_BUILTIN(__builtin_arm_stg, "vv*", "t", "mte")
TARGET_BUILTIN(__builtin_arm_subp, "Uiv*v*", "t", "mte")

// SME state function
BUILTIN(__builtin_arm_get_sme_state, "vULi*ULi*", "n")

// Memory Operations
TARGET_BUILTIN(__builtin_arm_mops_memset_tag, "v*v*iz", "", "mte,mops")

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to
///< enable code coverage analysis.
CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping
///< regions.
CODEGENOPT(MCDCCoverage , 1, 0) ///< Enable MC/DC code coverage criteria.

/// If -fpcc-struct-return or -freg-struct-return is specified.
ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default)
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@ def warn_invalid_feature_combination : Warning<
def warn_target_unrecognized_env : Warning<
"mismatch between architecture and environment in target triple '%0'; did you mean '%1'?">,
InGroup<InvalidCommandLineArgument>;
def warn_knl_knm_isa_support_removed : Warning<
"KNL, KNM related Intel Xeon Phi CPU's specific ISA's supports will be removed in LLVM 19.">,
InGroup<DiagGroup<"knl-knm-isa-support-removed">>;

// Source manager
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -786,4 +786,7 @@ def warn_android_unversioned_fallback : Warning<
" directories will not be used in Clang 19. Provide a versioned directory"
" for the target version or lower instead.">,
InGroup<DiagGroup<"android-unversioned-fallback">>;

def err_drv_triple_version_invalid : Error<
"version '%0' in target triple '%1' is invalid">;
}
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def err_verify_no_such_marker : Error<
def err_verify_missing_start : Error<
"cannot find start ('{{') of expected %0">;
def err_verify_missing_end : Error<
"cannot find end ('}}') of expected %0">;
"cannot find end ('%1') of expected %0">;
def err_verify_invalid_content : Error<
"invalid expected %0: %1">;
def err_verify_missing_regex : Error<
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,8 @@ def err_acc_invalid_clause : Error<"invalid OpenACC clause %0">;
def err_acc_missing_directive : Error<"expected OpenACC directive">;
def err_acc_invalid_open_paren
: Error<"expected clause-list or newline in OpenACC directive">;
def err_acc_invalid_default_clause_kind
: Error<"invalid value for 'default' clause; expected 'present' or 'none'">;

// OpenMP support.
def warn_pragma_omp_ignored : Warning<
Expand Down
16 changes: 8 additions & 8 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2253,6 +2253,8 @@ def warn_cxx17_compat_aggregate_init_paren_list : Warning<
def err_reference_bind_to_bitfield : Error<
"%select{non-const|volatile}0 reference cannot bind to "
"bit-field%select{| %1}2">;
def err_reference_bind_to_bitfield_in_cce : Error<
"reference cannot bind to bit-field in converted constant expression">;
def err_reference_bind_to_vector_element : Error<
"%select{non-const|volatile}0 reference cannot bind to vector element">;
def err_reference_bind_to_matrix_element : Error<
Expand Down Expand Up @@ -3415,6 +3417,8 @@ def warn_objc_redundant_literal_use : Warning<
def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", "
"\"local-dynamic\", \"initial-exec\" or \"local-exec\"">;

def err_attr_codemodel_arg : Error<"code model '%0' is not supported on this target">;

def err_aix_attr_unsupported_tls_model : Error<"TLS model '%0' is not yet supported on AIX">;

def err_tls_var_aligned_over_maximum : Error<
Expand Down Expand Up @@ -6158,23 +6162,19 @@ def err_illegal_initializer_type : Error<"illegal initializer type %0">;
def ext_init_list_type_narrowing : ExtWarn<
"type %0 cannot be narrowed to %1 in initializer list">,
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
// *_narrowing_const_reference diagnostics have the same messages, but are
// controlled by -Wc++11-narrowing-const-reference for narrowing involving a
// const reference.
def ext_init_list_type_narrowing_const_reference : ExtWarn<
"type %0 cannot be narrowed to %1 in initializer list">,
ext_init_list_type_narrowing.Summary>,
InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure;
def ext_init_list_variable_narrowing : ExtWarn<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def ext_init_list_variable_narrowing_const_reference : ExtWarn<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list">, InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure;
ext_init_list_variable_narrowing.Summary>, InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure;
def ext_init_list_constant_narrowing : ExtWarn<
"constant expression evaluates to %0 which cannot be narrowed to type %1">,
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def ext_init_list_constant_narrowing_const_reference : ExtWarn<
"constant expression evaluates to %0 which cannot be narrowed to type %1">,
ext_init_list_constant_narrowing.Summary>,
InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure;
def warn_init_list_type_narrowing : Warning<
"type %0 cannot be narrowed to %1 in initializer list in C++11">,
Expand Down Expand Up @@ -12064,7 +12064,7 @@ def warn_unsafe_buffer_variable : Warning<
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def warn_unsafe_buffer_operation : Warning<
"%select{unsafe pointer operation|unsafe pointer arithmetic|"
"unsafe buffer access|function introduces unsafe buffer manipulation}0">,
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of span::data}0">,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def note_unsafe_buffer_operation : Note<
"used%select{| in pointer arithmetic| in buffer access}0 here">;
Expand Down
28 changes: 18 additions & 10 deletions clang/include/clang/Basic/ObjCRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,24 @@ class ObjCRuntime {
bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) {
// The GNUstep runtime uses a newer dispatch method by default from
// version 1.6 onwards
if (getKind() == GNUstep && getVersion() >= VersionTuple(1, 6)) {
if (Arch == llvm::Triple::arm ||
Arch == llvm::Triple::x86 ||
Arch == llvm::Triple::x86_64)
return false;
}
else if ((getKind() == MacOSX) && isNonFragile() &&
(getVersion() >= VersionTuple(10, 0)) &&
(getVersion() < VersionTuple(10, 6)))
return Arch != llvm::Triple::x86_64;
if (getKind() == GNUstep) {
switch (Arch) {
case llvm::Triple::arm:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
return !(getVersion() >= VersionTuple(1, 6));
case llvm::Triple::aarch64:
case llvm::Triple::mips64:
return !(getVersion() >= VersionTuple(1, 9));
case llvm::Triple::riscv64:
return !(getVersion() >= VersionTuple(2, 2));
default:
return true;
}
} else if ((getKind() == MacOSX) && isNonFragile() &&
(getVersion() >= VersionTuple(10, 0)) &&
(getVersion() < VersionTuple(10, 6)))
return Arch != llvm::Triple::x86_64;
// Except for deployment target of 10.5 or less,
// Mac runtimes use legacy dispatch everywhere now.
return true;
Expand Down
Loading