5 changes: 4 additions & 1 deletion clang-tools-extra/clangd/ConfigYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include "llvm/Support/YAMLParser.h"
#include <optional>
#include <string>
#include <system_error>

namespace clang {
namespace clangd {
Expand Down Expand Up @@ -268,6 +267,10 @@ class Parser {
if (auto Value = boolValue(N, "BlockEnd"))
F.BlockEnd = *Value;
});
Dict.handle("DefaultArguments", [&](Node &N) {
if (auto Value = boolValue(N, "DefaultArguments"))
F.DefaultArguments = *Value;
});
Dict.handle("TypeNameLimit", [&](Node &N) {
if (auto Value = uint32Value(N, "TypeNameLimit"))
F.TypeNameLimit = *Value;
Expand Down
78 changes: 70 additions & 8 deletions clang-tools-extra/clangd/InlayHints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
#include "Config.h"
#include "HeuristicResolver.h"
#include "ParsedAST.h"
#include "Protocol.h"
#include "SourceCode.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
Expand All @@ -23,15 +25,22 @@
#include "clang/AST/Type.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <iterator>
#include <optional>
#include <string>

Expand Down Expand Up @@ -372,6 +381,23 @@ maybeDropCxxExplicitObjectParameters(ArrayRef<const ParmVarDecl *> Params) {
return Params;
}

template <typename R>
std::string joinAndTruncate(const R &Range, size_t MaxLength) {
std::string Out;
llvm::raw_string_ostream OS(Out);
llvm::ListSeparator Sep(", ");
for (auto &&Element : Range) {
OS << Sep;
if (Out.size() + Element.size() >= MaxLength) {
OS << "...";
break;
}
OS << Element;
}
OS.flush();
return Out;
}

struct Callee {
// Only one of Decl or Loc is set.
// Loc is for calls through function pointers.
Expand Down Expand Up @@ -422,7 +448,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
Callee.Decl = E->getConstructor();
if (!Callee.Decl)
return true;
processCall(Callee, {E->getArgs(), E->getNumArgs()});
processCall(Callee, E->getParenOrBraceRange().getEnd(),
{E->getArgs(), E->getNumArgs()});
return true;
}

Expand Down Expand Up @@ -495,7 +522,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
dyn_cast_or_null<CXXMethodDecl>(Callee.Decl))
if (IsFunctor || Method->hasCXXExplicitFunctionObjectParameter())
Args = Args.drop_front(1);
processCall(Callee, Args);
processCall(Callee, E->getRParenLoc(), Args);
return true;
}

Expand Down Expand Up @@ -709,10 +736,12 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
private:
using NameVec = SmallVector<StringRef, 8>;

void processCall(Callee Callee, llvm::ArrayRef<const Expr *> Args) {
void processCall(Callee Callee, SourceLocation RParenOrBraceLoc,
llvm::ArrayRef<const Expr *> Args) {
assert(Callee.Decl || Callee.Loc);

if (!Cfg.InlayHints.Parameters || Args.size() == 0)
if ((!Cfg.InlayHints.Parameters && !Cfg.InlayHints.DefaultArguments) ||
Args.size() == 0)
return;

// The parameter name of a move or copy constructor is not very interesting.
Expand All @@ -721,6 +750,9 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
if (Ctor->isCopyOrMoveConstructor())
return;

SmallVector<std::string> FormattedDefaultArgs;
bool HasNonDefaultArgs = false;

ArrayRef<const ParmVarDecl *> Params, ForwardedParams;
// Resolve parameter packs to their forwarded parameter
SmallVector<const ParmVarDecl *> ForwardedParamsStorage;
Expand Down Expand Up @@ -752,15 +784,44 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
}

StringRef Name = ParameterNames[I];
bool NameHint = shouldHintName(Args[I], Name);
bool ReferenceHint = shouldHintReference(Params[I], ForwardedParams[I]);

if (NameHint || ReferenceHint) {
const bool NameHint =
shouldHintName(Args[I], Name) && Cfg.InlayHints.Parameters;
const bool ReferenceHint =
shouldHintReference(Params[I], ForwardedParams[I]) &&
Cfg.InlayHints.Parameters;

const bool IsDefault = isa<CXXDefaultArgExpr>(Args[I]);
HasNonDefaultArgs |= !IsDefault;
if (IsDefault) {
if (Cfg.InlayHints.DefaultArguments) {
const auto SourceText = Lexer::getSourceText(
CharSourceRange::getTokenRange(Params[I]->getDefaultArgRange()),
AST.getSourceManager(), AST.getLangOpts());
const auto Abbrev =
(SourceText.size() > Cfg.InlayHints.TypeNameLimit ||
SourceText.contains("\n"))
? "..."
: SourceText;
if (NameHint)
FormattedDefaultArgs.emplace_back(
llvm::formatv("{0}: {1}", Name, Abbrev));
else
FormattedDefaultArgs.emplace_back(llvm::formatv("{0}", Abbrev));
}
} else if (NameHint || ReferenceHint) {
addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
InlayHintKind::Parameter, ReferenceHint ? "&" : "",
NameHint ? Name : "", ": ");
}
}

if (!FormattedDefaultArgs.empty()) {
std::string Hint =
joinAndTruncate(FormattedDefaultArgs, Cfg.InlayHints.TypeNameLimit);
addInlayHint(SourceRange{RParenOrBraceLoc}, HintSide::Left,
InlayHintKind::DefaultArgument,
HasNonDefaultArgs ? ", " : "", Hint, "");
}
}

static bool isSetter(const FunctionDecl *Callee, const NameVec &ParamNames) {
Expand Down Expand Up @@ -968,6 +1029,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
CHECK_KIND(Type, DeducedTypes);
CHECK_KIND(Designator, Designators);
CHECK_KIND(BlockEnd, BlockEnd);
CHECK_KIND(DefaultArgument, DefaultArguments);
#undef CHECK_KIND
}

Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clangd/Protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,7 @@ llvm::json::Value toJSON(const InlayHintKind &Kind) {
return 2;
case InlayHintKind::Designator:
case InlayHintKind::BlockEnd:
case InlayHintKind::DefaultArgument:
// This is an extension, don't serialize.
return nullptr;
}
Expand Down Expand Up @@ -1517,6 +1518,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) {
return "designator";
case InlayHintKind::BlockEnd:
return "block-end";
case InlayHintKind::DefaultArgument:
return "default-argument";
}
llvm_unreachable("Unknown clang.clangd.InlayHintKind");
};
Expand Down
9 changes: 9 additions & 0 deletions clang-tools-extra/clangd/Protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -1681,6 +1681,15 @@ enum class InlayHintKind {
/// This is a clangd extension.
BlockEnd = 4,

/// An inlay hint that is for a default argument.
///
/// An example of a parameter hint for a default argument:
/// void foo(bool A = true);
/// foo(^);
/// Adds an inlay hint "A: true".
/// This is a clangd extension.
DefaultArgument = 6,

/// Other ideas for hints that are not currently implemented:
///
/// * Chaining hints, showing the types of intermediate expressions
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/URI.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,8 @@ typedef llvm::Registry<URIScheme> URISchemeRegistry;
} // namespace clangd
} // namespace clang

namespace llvm {
extern template class Registry<clang::clangd::URIScheme>;
} // namespace llvm

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_URI_H
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/refactor/Tweak.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,8 @@ prepareTweak(StringRef ID, const Tweak::Selection &S,
} // namespace clangd
} // namespace clang

namespace llvm {
extern template class Registry<clang::clangd::Tweak>;
} // namespace llvm

#endif
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/test/log.test
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# RUN: env CLANGD_FLAGS=-compile-commands-dir=no-such-dir not clangd -lit-test </dev/null 2>&1 >/dev/null | FileCheck %s
CHECK: I[{{.*}}]{{.*}} clangd version {{.*}}
CHECK: Working directory: {{.*}}
CHECK: argv[0]: clangd
CHECK: argv[0]: {{.*}}clangd
CHECK: argv[1]: -lit-test
CHECK: CLANGD_FLAGS: -compile-commands-dir=no-such-dir
CHECK: E[{{.*}}] Path specified by --compile-commands-dir does not exist.
Expand Down
73 changes: 73 additions & 0 deletions clang-tools-extra/clangd/unittests/InlayHintTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
#include "support/Context.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <optional>
#include <string>
#include <utility>
#include <vector>

namespace clang {
Expand Down Expand Up @@ -81,6 +84,7 @@ Config noHintsConfig() {
C.InlayHints.DeducedTypes = false;
C.InlayHints.Designators = false;
C.InlayHints.BlockEnd = false;
C.InlayHints.DefaultArguments = false;
return C;
}

Expand Down Expand Up @@ -1465,6 +1469,75 @@ TEST(TypeHints, DefaultTemplateArgs) {
ExpectedHint{": A<float>", "binding"});
}

TEST(DefaultArguments, Smoke) {
Config Cfg;
Cfg.InlayHints.Parameters =
true; // To test interplay of parameters and default parameters
Cfg.InlayHints.DeducedTypes = false;
Cfg.InlayHints.Designators = false;
Cfg.InlayHints.BlockEnd = false;

Cfg.InlayHints.DefaultArguments = true;
WithContextValue WithCfg(Config::Key, std::move(Cfg));

const auto *Code = R"cpp(
int foo(int A = 4) { return A; }
int bar(int A, int B = 1, bool C = foo($default1[[)]]) { return A; }
int A = bar($explicit[[2]]$default2[[)]];
void baz(int = 5) { if (false) baz($unnamed[[)]]; };
)cpp";

assertHints(InlayHintKind::DefaultArgument, Code,
ExpectedHint{"A: 4", "default1", Left},
ExpectedHint{", B: 1, C: foo()", "default2", Left},
ExpectedHint{"5", "unnamed", Left});

assertHints(InlayHintKind::Parameter, Code,
ExpectedHint{"A: ", "explicit", Left});
}

TEST(DefaultArguments, WithoutParameterNames) {
Config Cfg;
Cfg.InlayHints.Parameters = false; // To test just default args this time
Cfg.InlayHints.DeducedTypes = false;
Cfg.InlayHints.Designators = false;
Cfg.InlayHints.BlockEnd = false;

Cfg.InlayHints.DefaultArguments = true;
WithContextValue WithCfg(Config::Key, std::move(Cfg));

const auto *Code = R"cpp(
struct Baz {
Baz(float a = 3 //
+ 2);
};
struct Foo {
Foo(int, Baz baz = //
Baz{$abbreviated[[}]]
//
) {}
};
int main() {
Foo foo1(1$paren[[)]];
Foo foo2{2$brace1[[}]];
Foo foo3 = {3$brace2[[}]];
auto foo4 = Foo{4$brace3[[}]];
}
)cpp";

assertHints(InlayHintKind::DefaultArgument, Code,
ExpectedHint{"...", "abbreviated", Left},
ExpectedHint{", Baz{}", "paren", Left},
ExpectedHint{", Baz{}", "brace1", Left},
ExpectedHint{", Baz{}", "brace2", Left},
ExpectedHint{", Baz{}", "brace3", Left});

assertHints(InlayHintKind::Parameter, Code);
}

TEST(TypeHints, Deduplication) {
assertTypeHints(R"cpp(
template <typename T>
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ Improvements to clangd
Inlay hints
^^^^^^^^^^^

- Added `DefaultArguments` Inlay Hints option.

Diagnostics
^^^^^^^^^^^

Expand Down Expand Up @@ -195,6 +197,10 @@ Changes in existing checks
<clang-tidy/checks/modernize/loop-convert>` check to fix false positive when
using loop variable in initializer of lambda capture.

- Improved :doc:`misc-use-internal-linkage
<clang-tidy/checks/misc/use-internal-linkage>` check to insert ``static`` keyword
before type qualifiers such as ``const`` and ``volatile``.

- Improved :doc:`modernize-min-max-use-initializer-list
<clang-tidy/checks/modernize/min-max-use-initializer-list>` check by fixing
a false positive when only an implicit conversion happened inside an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Violating the naming rules above results in undefined behavior.
int _g(); // disallowed in global namespace only

The check can also be inverted, i.e. it can be configured to flag any
identifier that is _not_ a reserved identifier. This mode is for use by e.g.
identifier that is *not* a reserved identifier. This mode is for use by e.g.
standard library implementors, to ensure they don't infringe on the user
namespace.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ using IncludeSpellingStrategy = llvm::Registry<IncludeSpeller>;
std::string spellHeader(const IncludeSpeller::Input &Input);
} // namespace clang::include_cleaner

namespace llvm {
extern template class Registry<clang::include_cleaner::IncludeSpeller>;
} // namespace llvm

#endif
10 changes: 10 additions & 0 deletions clang-tools-extra/include-cleaner/test/tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,13 @@ int x = foo();
// RUN: clang-include-cleaner -edit --ignore-headers="foobar\.h,foo\.h" %t.cpp -- -I%S/Inputs/
// RUN: FileCheck --match-full-lines --check-prefix=EDIT2 %s < %t.cpp
// EDIT2-NOT: {{^}}#include "foo.h"{{$}}

// RUN: rm -rf %t.dir && mkdir -p %t.dir
// RUN: cp %s %t.cpp
// RUN: echo "[{\"directory\":\"%t.dir\",\"file\":\"../%{t:stem}.tmp.cpp\",\"command\":\":clang++ -I%S/Inputs/ ../%{t:stem}.tmp.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t.dir/compile_commands.json
// RUN: pushd %t.dir
// RUN: clang-include-cleaner -p %{t:stem}.tmp.dir -edit ../%{t:stem}.tmp.cpp
// RUN: popd
// RUN: FileCheck --match-full-lines --check-prefix=EDIT3 %s < %t.cpp
// EDIT3: #include "foo.h"
// EDIT3-NOT: {{^}}#include "foobar.h"{{$}}
70 changes: 63 additions & 7 deletions clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,11 @@ class Action : public clang::ASTFrontendAction {
if (!HTMLReportPath.empty())
writeHTML();

llvm::StringRef Path =
SM.getFileEntryRefForID(SM.getMainFileID())->getName();
assert(!Path.empty() && "Main file path not known?");
// Source File's path of compiler invocation, converted to absolute path.
llvm::SmallString<256> AbsPath(
SM.getFileEntryRefForID(SM.getMainFileID())->getName());
assert(!AbsPath.empty() && "Main file path not known?");
SM.getFileManager().makeAbsolutePath(AbsPath);
llvm::StringRef Code = SM.getBufferData(SM.getMainFileID());

auto Results =
Expand All @@ -185,7 +187,7 @@ class Action : public clang::ASTFrontendAction {
Results.Missing.clear();
if (!Remove)
Results.Unused.clear();
std::string Final = fixIncludes(Results, Path, Code, getStyle(Path));
std::string Final = fixIncludes(Results, AbsPath, Code, getStyle(AbsPath));

if (Print.getNumOccurrences()) {
switch (Print) {
Expand All @@ -202,7 +204,7 @@ class Action : public clang::ASTFrontendAction {
}

if (!Results.Missing.empty() || !Results.Unused.empty())
EditedFiles.try_emplace(Path, Final);
EditedFiles.try_emplace(AbsPath, Final);
}

void writeHTML() {
Expand Down Expand Up @@ -280,6 +282,48 @@ std::function<bool(llvm::StringRef)> headerFilter() {
};
}

// Maps absolute path of each files of each compilation commands to the
// absolute path of the input file.
llvm::Expected<std::map<std::string, std::string>>
mapInputsToAbsPaths(clang::tooling::CompilationDatabase &CDB,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
const std::vector<std::string> &Inputs) {
std::map<std::string, std::string> CDBToAbsPaths;
// Factory.editedFiles()` will contain the final code, along with the
// path given in the compilation database. That path can be
// absolute or relative, and if it is relative, it is relative to the
// "Directory" field in the compilation database. We need to make it
// absolute to write the final code to the correct path.
for (auto &Source : Inputs) {
llvm::SmallString<256> AbsPath(Source);
if (auto Err = VFS->makeAbsolute(AbsPath)) {
llvm::errs() << "Failed to get absolute path for " << Source << " : "
<< Err.message() << '\n';
return llvm::errorCodeToError(Err);
}
std::vector<clang::tooling::CompileCommand> Cmds =
CDB.getCompileCommands(AbsPath);
if (Cmds.empty()) {
// It should be found in the compilation database, even user didn't
// specify the compilation database, the `FixedCompilationDatabase` will
// create an entry from the arguments. So it is an error if we can't
// find the compile commands.
std::string ErrorMsg =
llvm::formatv("No compile commands found for {0}", AbsPath).str();
llvm::errs() << ErrorMsg << '\n';
return llvm::make_error<llvm::StringError>(
ErrorMsg, llvm::inconvertibleErrorCode());
}
for (const auto &Cmd : Cmds) {
llvm::SmallString<256> CDBPath(Cmd.Filename);
std::string Directory(Cmd.Directory);
llvm::sys::fs::make_absolute(Cmd.Directory, CDBPath);
CDBToAbsPaths[std::string(CDBPath)] = std::string(AbsPath);
}
}
return CDBToAbsPaths;
}

} // namespace
} // namespace include_cleaner
} // namespace clang
Expand All @@ -305,8 +349,16 @@ int main(int argc, const char **argv) {
}
}

clang::tooling::ClangTool Tool(OptionsParser->getCompilations(),
OptionsParser->getSourcePathList());
auto VFS = llvm::vfs::getRealFileSystem();
auto &CDB = OptionsParser->getCompilations();
// CDBToAbsPaths is a map from the path in the compilation database to the
// writable absolute path of the file.
auto CDBToAbsPaths =
mapInputsToAbsPaths(CDB, VFS, OptionsParser->getSourcePathList());
if (!CDBToAbsPaths)
return 1;

clang::tooling::ClangTool Tool(CDB, OptionsParser->getSourcePathList());

auto HeaderFilter = headerFilter();
if (!HeaderFilter)
Expand All @@ -316,6 +368,10 @@ int main(int argc, const char **argv) {
if (Edit) {
for (const auto &NameAndContent : Factory.editedFiles()) {
llvm::StringRef FileName = NameAndContent.first();
if (auto It = CDBToAbsPaths->find(FileName.str());
It != CDBToAbsPaths->end())
FileName = It->second;

const std::string &FinalCode = NameAndContent.second;
if (auto Err = llvm::writeToOutput(
FileName, [&](llvm::raw_ostream &OS) -> llvm::Error {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: not clang-query --invalid-arg 2>&1 | FileCheck %s

// CHECK: error: clang-query{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: 'clang-query{{(\.exe)?}} --help'
// CHECK: error: clang-query{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: '{{.*}}clang-query{{(\.exe)?}} --help'
// CHECK-NEXT: clang-query{{(\.exe)?}}: Did you mean '--extra-arg'?
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,41 @@ void func_cpp_inc();
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'func_cpp_inc'
// CHECK-FIXES: static void func_cpp_inc();

int* func_cpp_inc_return_ptr();
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'func_cpp_inc_return_ptr'
// CHECK-FIXES: static int* func_cpp_inc_return_ptr();

const int* func_cpp_inc_return_const_ptr();
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: function 'func_cpp_inc_return_const_ptr'
// CHECK-FIXES: static const int* func_cpp_inc_return_const_ptr();

int const* func_cpp_inc_return_ptr_const();
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: function 'func_cpp_inc_return_ptr_const'
// CHECK-FIXES: static int const* func_cpp_inc_return_ptr_const();

int * const func_cpp_inc_return_const();
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: function 'func_cpp_inc_return_const'
// CHECK-FIXES: static int * const func_cpp_inc_return_const();

volatile const int* func_cpp_inc_return_volatile_const_ptr();
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: function 'func_cpp_inc_return_volatile_const_ptr'
// CHECK-FIXES: static volatile const int* func_cpp_inc_return_volatile_const_ptr();

[[nodiscard]] void func_nodiscard();
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: function 'func_nodiscard'
// CHECK-FIXES: {{\[\[nodiscard\]\]}} static void func_nodiscard();

#define NDS [[nodiscard]]
#define NNDS

NDS void func_nds();
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: function 'func_nds'
// CHECK-FIXES: NDS static void func_nds();

NNDS void func_nnds();
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: function 'func_nnds'
// CHECK-FIXES: NNDS static void func_nnds();

#include "func_cpp.inc"

void func_h_inc();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ T global_template;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: variable 'global_template'
// CHECK-FIXES: static T global_template;

int const* ptr_const_star;
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: variable 'ptr_const_star'
// CHECK-FIXES: static int const* ptr_const_star;

const int* const_ptr_star;
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: variable 'const_ptr_star'
// CHECK-FIXES: static const int* const_ptr_star;

const volatile int* const_volatile_ptr_star;
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: variable 'const_volatile_ptr_star'
// CHECK-FIXES: static const volatile int* const_volatile_ptr_star;

int gloabl_header;

extern int global_extern;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,9 @@ struct prefer_underscore_version_flip {
size_t find(const char *s, size_t pos = 0) const;
};

struct prefer_underscore_version_inherit : public string_like {
bool startsWith(const char *s) const;
};

void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss,
string_like sl, string_like_camel slc, prefer_underscore_version puv,
prefer_underscore_version_flip puvf,
prefer_underscore_version_inherit puvi) {
prefer_underscore_version_flip puvf) {
s.find("a") == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of find() == 0
// CHECK-FIXES: s.starts_with("a");
Expand Down Expand Up @@ -153,12 +148,6 @@ void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss,
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
// CHECK-FIXES: puvf.starts_with("a");

// Here, the subclass has startsWith, the superclass has starts_with.
// We prefer the version from the subclass.
puvi.find("a") == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use startsWith
// CHECK-FIXES: puvi.startsWith("a");

s.compare(0, 1, "a") == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of compare() == 0
// CHECK-FIXES: s.starts_with("a");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: not clang-tidy --invalid-arg 2>&1 | FileCheck %s

// CHECK: error: clang-tidy{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: 'clang-tidy{{(\.exe)?}} --help'
// CHECK: error: clang-tidy{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: '{{.*}}clang-tidy{{(\.exe)?}} --help'
// CHECK-NEXT: clang-tidy{{(\.exe)?}}: Did you mean '--extra-arg'?
25 changes: 25 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5505,6 +5505,31 @@ the configuration (without a prefix: ``Auto``).
}
}

.. _RemoveEmptyLinesInUnwrappedLines:

**RemoveEmptyLinesInUnwrappedLines** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <RemoveEmptyLinesInUnwrappedLines>`
Remove empty lines within unwrapped lines.

.. code-block:: c++

false: true:

int c vs. int c = a + b;

= a + b;

enum : unsigned vs. enum : unsigned {
AA = 0,
{ BB
AA = 0, } myEnum;
BB
} myEnum;

while ( vs. while (true) {
}
true) {
}

.. _RemoveParentheses:

**RemoveParentheses** (``RemoveParenthesesStyle``) :versionbadge:`clang-format 17` :ref:`¶ <RemoveParentheses>`
Expand Down
4 changes: 2 additions & 2 deletions clang/docs/LibASTMatchersReference.html
Original file line number Diff line number Diff line change
Expand Up @@ -7239,9 +7239,9 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
void z(Y y, X x) { y.m(); x.m(); x.g(); (g()).m(); }
cxxMemberCallExpr(onImplicitObjectArgument(hasType(
cxxRecordDecl(hasName("Y")))))
matches `y.m()`, `x.m()` and (g()).m(), but not `x.g()`.
matches `y.m()`, `x.m()` and (`g()).m()`, but not `x.g()`).
cxxMemberCallExpr(on(callExpr()))
does not match `(g()).m()`, because the parens are not ignored.
only matches `(g()).m()` (the parens are ignored).

FIXME: Overload to allow directly matching types?
</pre></td></tr>
Expand Down
30 changes: 25 additions & 5 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,24 @@ C++ Specific Potentially Breaking Changes
// Was error, now evaluates to false.
constexpr bool b = f() == g();
- Clang will now correctly not consider pointers to non classes for covariance.
- Clang will now correctly not consider pointers to non classes for covariance
and disallow changing return type to a type that doesn't have the same or less cv-qualifications.

.. code-block:: c++

struct A {
virtual const int *f() const;
virtual const std::string *g() const;
};
struct B : A {
// Return type has less cv-qualification but doesn't point to a class.
// Error will be generated.
int *f() const override;
// Return type doesn't have more cv-qualification also not the same or
// less cv-qualification.
// Error will be generated.
volatile std::string *g() const override;
};
- The warning ``-Wdeprecated-literal-operator`` is now on by default, as this is
Expand Down Expand Up @@ -265,6 +272,7 @@ Non-comprehensive list of changes in this release
``__builtin_signbit`` can now be used in constant expressions.
- Plugins can now define custom attributes that apply to statements
as well as declarations.
- ``__builtin_abs`` function can now be used in constant expressions.

New Compiler Flags
------------------
Expand Down Expand Up @@ -411,7 +419,7 @@ Improvements to Clang's diagnostics
- The warning for an unsupported type for a named register variable is now phrased ``unsupported type for named register variable``,
instead of ``bad type for named register variable``. This makes it clear that the type is not supported at all, rather than being
suboptimal in some way the error fails to mention (#GH111550).

- Clang now emits a ``-Wdepredcated-literal-operator`` diagnostic, even if the
name was a reserved name, which we improperly allowed to suppress the
diagnostic.
Expand All @@ -431,6 +439,7 @@ Bug Fixes in This Version
- Fixed a crash when trying to transform a dependent address space type. Fixes #GH101685.
- Fixed a crash when diagnosing format strings and encountering an empty
delimited escape sequence (e.g., ``"\o{}"``). #GH102218
- Fixed a crash using ``__array_rank`` on 64-bit targets. (#GH113044).
- The warning emitted for an unsupported register variable type now points to
the unsupported type instead of the ``register`` keyword (#GH109776).

Expand Down Expand Up @@ -499,7 +508,7 @@ Bug Fixes to C++ Support
- Clang no longer tries to capture non-odr used default arguments of template parameters of generic lambdas (#GH107048)
- Fixed a bug where defaulted comparison operators would remove ``const`` from base classes. (#GH102588)
- Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134)
- A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361)
- A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361), (#GH112352)
- Fixed a crash in the typo correction of an invalid CTAD guide. (#GH107887)
- Fixed a crash when clang tries to subtitute parameter pack while retaining the parameter
pack. (#GH63819), (#GH107560)
Expand Down Expand Up @@ -530,6 +539,10 @@ Bug Fixes to C++ Support
certain situations. (#GH47400), (#GH90896)
- Fix erroneous templated array size calculation leading to crashes in generated code. (#GH41441)
- During the lookup for a base class name, non-type names are ignored. (#GH16855)
- Fix a crash when recovering an invalid expression involving an explicit object member conversion operator. (#GH112559)
- Clang incorrectly considered a class with an anonymous union member to not be
const-default-constructible even if a union member has a default member initializer.
(#GH95854).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -612,6 +625,11 @@ X86 Support
Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^

- In the ARM Target, the frame pointer (FP) of a leaf function can be retained
by using the ``-fno-omit-frame-pointer`` option. If you want to eliminate the FP
in leaf functions after enabling ``-fno-omit-frame-pointer``, you can do so by adding
the ``-momit-leaf-frame-pointer`` option.

Android Support
^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -687,8 +705,10 @@ clang-format
- Adds ``BreakBinaryOperations`` option.
- Adds ``TemplateNames`` option.
- Adds ``AlignFunctionDeclarations`` option to ``AlignConsecutiveDeclarations``.
- Adds ``IndentOnly`` suboption to ``ReflowComments`` to fix the indentation of multi-line comments
without touching their contents, renames ``false`` to ``Never``, and ``true`` to ``Always``.
- Adds ``IndentOnly`` suboption to ``ReflowComments`` to fix the indentation of
multi-line comments without touching their contents, renames ``false`` to
``Never``, and ``true`` to ``Always``.
- Adds ``RemoveEmptyLinesInUnwrappedLines`` option.

libclang
--------
Expand Down
2 changes: 1 addition & 1 deletion clang/docs/analyzer/user-docs/CommandLineUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Command Line Usage: scan-build and CodeChecker
==============================================

This document provides guidelines for running the static analyzer from the command line on whole projects.
CodeChecker and scan-build are two CLI tools for using CSA on multiple files (tranlation units).
CodeChecker and scan-build are two CLI tools for using CSA on multiple files (translation units).
Both provide a way of driving the analyzer, detecting compilation flags, and generating reports.
CodeChecker is more actively maintained, provides heuristics for working with multiple versions of popular compilers and it also comes with a web-based GUI for viewing, filtering, categorizing and suppressing the results.
Therefore CodeChecker is recommended in case you need any of the above features or just more customizability in general.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang-c/Index.h
Original file line number Diff line number Diff line change
Expand Up @@ -2980,7 +2980,7 @@ enum CXTypeKind {
CXType_Atomic = 177,
CXType_BTFTagAttributed = 178,

// HLSL Types
/* HLSL Types */
CXType_HLSLResource = 179,
CXType_HLSLAttributedResource = 180
};
Expand Down
23 changes: 13 additions & 10 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
}

void anchor() override;

protected:
template <typename EntryType> struct SpecEntryTraits {
using DeclType = EntryType;
Expand Down Expand Up @@ -769,13 +770,22 @@ class RedeclarableTemplateDecl : public TemplateDecl,
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
}

void loadLazySpecializationsImpl() const;
void loadLazySpecializationsImpl(bool OnlyPartial = false) const;

bool loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
TemplateParameterList *TPL = nullptr) const;

template <class EntryType, typename ...ProfileArguments>
typename SpecEntryTraits<EntryType>::DeclType*
findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
void *&InsertPos, ProfileArguments &&...ProfileArgs);

template <class EntryType, typename... ProfileArguments>
typename SpecEntryTraits<EntryType>::DeclType *
findSpecializationLocally(llvm::FoldingSetVector<EntryType> &Specs,
void *&InsertPos,
ProfileArguments &&...ProfileArgs);

template <class Derived, class EntryType>
void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
EntryType *Entry, void *InsertPos);
Expand All @@ -787,13 +797,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// directly instantiated (or null).
RedeclarableTemplateDecl *InstantiatedFromMember = nullptr;

/// If non-null, points to an array of specializations (including
/// partial specializations) known only by their external declaration IDs.
///
/// The first value in the array is the number of specializations/partial
/// specializations that follow.
GlobalDeclID *LazySpecializations = nullptr;

/// The set of "injected" template arguments used within this
/// template.
///
Expand Down Expand Up @@ -2299,7 +2302,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
friend class TemplateDeclInstantiator;

/// Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations() const;
void LoadLazySpecializations(bool OnlyPartial = false) const;

/// Get the underlying class declarations of the template.
CXXRecordDecl *getTemplatedDecl() const {
Expand Down Expand Up @@ -3060,7 +3063,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
friend class ASTDeclWriter;

/// Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations() const;
void LoadLazySpecializations(bool OnlyPartial = false) const;

/// Get the underlying variable declarations of the template.
VarDecl *getTemplatedDecl() const {
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -6777,6 +6777,17 @@ class AtomicExpr : public Expr {
getOp() <= AO__opencl_atomic_store;
}

bool isHIP() const {
return Op >= AO__hip_atomic_compare_exchange_strong &&
Op <= AO__hip_atomic_store;
}

/// Return true if atomics operations targeting allocations in private memory
/// are undefined.
bool threadPrivateMemoryAtomicsAreUndefined() const {
return isOpenCL() || isHIP();
}

SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }

Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -876,13 +876,13 @@ class CXXTypeidExpr : public Expr {

/// Best-effort check if the expression operand refers to a most derived
/// object. This is not a strong guarantee.
bool isMostDerived(ASTContext &Context) const;
bool isMostDerived(const ASTContext &Context) const;

bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); }

/// Retrieves the type operand of this typeid() expression after
/// various required adjustments (removing reference types, cv-qualifiers).
QualType getTypeOperand(ASTContext &Context) const;
QualType getTypeOperand(const ASTContext &Context) const;

/// Retrieve source information for the type operand.
TypeSourceInfo *getTypeOperandSourceInfo() const {
Expand Down
63 changes: 50 additions & 13 deletions clang/include/clang/AST/ExternalASTSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <new>
#include <optional>
#include <utility>

Expand Down Expand Up @@ -150,6 +152,21 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
virtual bool
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);

/// Load all the external specializations for the Decl \param D if \param
/// OnlyPartial is false. Otherwise, load all the external **partial**
/// specializations for the \param D.
///
/// Return true if any new specializations get loaded. Return false otherwise.
virtual bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial);

/// Load all the specializations for the Decl \param D with the same template
/// args specified by \param TemplateArgs.
///
/// Return true if any new specializations get loaded. Return false otherwise.
virtual bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs);

/// Ensures that the table of all visible declarations inside this
/// context is up to date.
///
Expand Down Expand Up @@ -326,45 +343,65 @@ struct LazyOffsetPtr {
///
/// If the low bit is clear, a pointer to the AST node. If the low
/// bit is set, the upper 63 bits are the offset.
mutable uint64_t Ptr = 0;
static constexpr size_t DataSize = std::max(sizeof(uint64_t), sizeof(T *));
alignas(uint64_t) alignas(T *) mutable unsigned char Data[DataSize] = {};

unsigned char GetLSB() const {
return Data[llvm::sys::IsBigEndianHost ? DataSize - 1 : 0];
}

template <typename U> U &As(bool New) const {
unsigned char *Obj =
Data + (llvm::sys::IsBigEndianHost ? DataSize - sizeof(U) : 0);
if (New)
return *new (Obj) U;
return *std::launder(reinterpret_cast<U *>(Obj));
}

T *&GetPtr() const { return As<T *>(false); }
uint64_t &GetU64() const { return As<uint64_t>(false); }
void SetPtr(T *Ptr) const { As<T *>(true) = Ptr; }
void SetU64(uint64_t U64) const { As<uint64_t>(true) = U64; }

public:
LazyOffsetPtr() = default;
explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) {}
explicit LazyOffsetPtr(T *Ptr) : Data() { SetPtr(Ptr); }

explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) {
explicit LazyOffsetPtr(uint64_t Offset) : Data() {
assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
if (Offset == 0)
Ptr = 0;
SetPtr(nullptr);
else
SetU64((Offset << 1) | 0x01);
}

LazyOffsetPtr &operator=(T *Ptr) {
this->Ptr = reinterpret_cast<uint64_t>(Ptr);
SetPtr(Ptr);
return *this;
}

LazyOffsetPtr &operator=(uint64_t Offset) {
assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
if (Offset == 0)
Ptr = 0;
SetPtr(nullptr);
else
Ptr = (Offset << 1) | 0x01;
SetU64((Offset << 1) | 0x01);

return *this;
}

/// Whether this pointer is non-NULL.
///
/// This operation does not require the AST node to be deserialized.
explicit operator bool() const { return Ptr != 0; }
explicit operator bool() const { return isOffset() || GetPtr() != nullptr; }

/// Whether this pointer is non-NULL.
///
/// This operation does not require the AST node to be deserialized.
bool isValid() const { return Ptr != 0; }
bool isValid() const { return isOffset() || GetPtr() != nullptr; }

/// Whether this pointer is currently stored as an offset.
bool isOffset() const { return Ptr & 0x01; }
bool isOffset() const { return GetLSB() & 0x01; }

/// Retrieve the pointer to the AST node that this lazy pointer points to.
///
Expand All @@ -375,17 +412,17 @@ struct LazyOffsetPtr {
if (isOffset()) {
assert(Source &&
"Cannot deserialize a lazy pointer without an AST source");
Ptr = reinterpret_cast<uint64_t>((Source->*Get)(OffsT(Ptr >> 1)));
SetPtr((Source->*Get)(OffsT(GetU64() >> 1)));
}
return reinterpret_cast<T*>(Ptr);
return GetPtr();
}

/// Retrieve the address of the AST node pointer. Deserializes the pointee if
/// necessary.
T **getAddressOfPointer(ExternalASTSource *Source) const {
// Ensure the integer is in pointer form.
(void)get(Source);
return reinterpret_cast<T**>(&Ptr);
return &GetPtr();
}
};

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -6320,6 +6320,10 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == HLSLAttributedResource;
}

// Returns handle type from HLSL resource, if the type is a resource
static const HLSLAttributedResourceType *
findHandleTypeOnResource(const Type *RT);
};

class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -4197,9 +4197,9 @@ AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>,
/// \endcode
/// cxxMemberCallExpr(onImplicitObjectArgument(hasType(
/// cxxRecordDecl(hasName("Y")))))
/// matches `y.m()`, `x.m()` and (g()).m(), but not `x.g()`.
/// matches `y.m()`, `x.m()` and (`g()).m()`, but not `x.g()`).
/// cxxMemberCallExpr(on(callExpr()))
/// does not match `(g()).m()`, because the parens are not ignored.
/// only matches `(g()).m()` (the parens are ignored).
///
/// FIXME: Overload to allow directly matching types?
AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/ASTMatchers/ASTMatchersMacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H
#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H

#include "clang/Support/Compiler.h"

/// AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) { ... }
/// defines a zero parameter function named DefineMatcher() that returns a
/// ReturnType object.
Expand Down Expand Up @@ -367,7 +369,7 @@
static QualType (T::*value())() const { return &T::FunctionName; } \
}; \
} \
extern const ::clang::ast_matchers::internal:: \
CLANG_ABI extern const ::clang::ast_matchers::internal:: \
TypeTraversePolymorphicMatcher< \
QualType, \
::clang::ast_matchers::internal::TypeMatcher##MatcherName##Getter, \
Expand Down Expand Up @@ -407,7 +409,7 @@
static TypeLoc (T::*value())() const { return &T::FunctionName##Loc; } \
}; \
} \
extern const ::clang::ast_matchers::internal:: \
CLANG_ABI extern const ::clang::ast_matchers::internal:: \
TypeTraversePolymorphicMatcher< \
TypeLoc, \
::clang::ast_matchers::internal:: \
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Basic/AArch64SVEACLETypes.def
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ SVE_VECTOR_TYPE_FLOAT("__SVFloat64_t", "__SVFloat64_t", SveFloat64, SveFloat64Ty

SVE_VECTOR_TYPE_BFLOAT("__SVBfloat16_t", "__SVBfloat16_t", SveBFloat16, SveBFloat16Ty, 8, 16, 1)

// This is a 8 bits opaque type.
SVE_VECTOR_TYPE_INT("__SVMfloat8_t", "__SVMfloat8_t", SveMFloat8, SveMFloat8Ty, 16, 8, 1, false)

//
// x2
//
Expand All @@ -135,6 +138,8 @@ SVE_VECTOR_TYPE_FLOAT("__clang_svfloat64x2_t", "svfloat64x2_t", SveFloat64x2, Sv

SVE_VECTOR_TYPE_BFLOAT("__clang_svbfloat16x2_t", "svbfloat16x2_t", SveBFloat16x2, SveBFloat16x2Ty, 8, 16, 2)

SVE_VECTOR_TYPE_INT("__clang_svmfloat8x2_t", "svmfloat8x2_t", SveMFloat8x2, SveMFloat8x2Ty, 16, 8, 2, false)

//
// x3
//
Expand All @@ -155,6 +160,8 @@ SVE_VECTOR_TYPE_FLOAT("__clang_svfloat64x3_t", "svfloat64x3_t", SveFloat64x3, Sv

SVE_VECTOR_TYPE_BFLOAT("__clang_svbfloat16x3_t", "svbfloat16x3_t", SveBFloat16x3, SveBFloat16x3Ty, 8, 16, 3)

SVE_VECTOR_TYPE_INT("__clang_svmfloat8x3_t", "svmfloat8x3_t", SveMFloat8x3, SveMFloat8x3Ty, 16, 8, 3, false)

//
// x4
//
Expand All @@ -175,6 +182,8 @@ SVE_VECTOR_TYPE_FLOAT("__clang_svfloat64x4_t", "svfloat64x4_t", SveFloat64x4, Sv

SVE_VECTOR_TYPE_BFLOAT("__clang_svbfloat16x4_t", "svbfloat16x4_t", SveBFloat16x4, SveBFloat16x4Ty, 8, 16, 4)

SVE_VECTOR_TYPE_INT("__clang_svmfloat8x4_t", "svmfloat8x4_t", SveMFloat8x4, SveMFloat8x4Ty, 16, 8, 4, false)

SVE_PREDICATE_TYPE_ALL("__SVBool_t", "__SVBool_t", SveBool, SveBoolTy, 16, 1)
SVE_PREDICATE_TYPE_ALL("__clang_svboolx2_t", "svboolx2_t", SveBoolx2, SveBoolx2Ty, 16, 2)
SVE_PREDICATE_TYPE_ALL("__clang_svboolx4_t", "svboolx4_t", SveBoolx4, SveBoolx4Ty, 16, 4)
Expand Down
25 changes: 25 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -4593,6 +4593,31 @@ def HLSLResourceBinding: InheritableAttr {
let LangOpts = [HLSL];
let Args = [StringArgument<"Slot">, StringArgument<"Space", 1>];
let Documentation = [HLSLResourceBindingDocs];
let AdditionalMembers = [{
public:
enum class RegisterType : unsigned { SRV, UAV, CBuffer, Sampler, C, I };

private:
RegisterType RegType;
unsigned SlotNumber;
unsigned SpaceNumber;

public:
void setBinding(RegisterType RT, unsigned SlotNum, unsigned SpaceNum) {
RegType = RT;
SlotNumber = SlotNum;
SpaceNumber = SpaceNum;
}
RegisterType getRegisterType() const {
return RegType;
}
unsigned getSlotNumber() const {
return SlotNumber;
}
unsigned getSpaceNumber() const {
return SpaceNumber;
}
}];
}

def HLSLPackOffset: HLSLAnnotationAttr {
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -2669,7 +2669,7 @@ sign. For example:

.. code-block:: c++

__attribute__((target_clones("sha2+memtag2", "fcma+sve2-pmull128")))
__attribute__((target_clones("sha2+memtag", "fcma+sve2-pmull128")))
void foo() {}

For every multiversioned function a ``default`` (fallback) implementation
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -2714,6 +2714,7 @@ def Abs : IntMathTemplate, LibBuiltin<"stdlib.h"> {
let Attributes = [NoThrow, Const];
let Prototype = "T(T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}

def Calloc : LibBuiltin<"stdlib.h"> {
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@ TARGET_BUILTIN(__builtin_amdgcn_frexp_exph, "sh", "nc", "16-bit-insts")
TARGET_BUILTIN(__builtin_amdgcn_fracth, "hh", "nc", "16-bit-insts")
TARGET_BUILTIN(__builtin_amdgcn_classh, "bhi", "nc", "16-bit-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_memrealtime, "WUi", "n", "s-memrealtime")
TARGET_BUILTIN(__builtin_amdgcn_mov_dpp, "iiIiIiIiIb", "nc", "dpp")
TARGET_BUILTIN(__builtin_amdgcn_update_dpp, "iiiIiIiIiIb", "nc", "dpp")
TARGET_BUILTIN(__builtin_amdgcn_mov_dpp, "iiIiIiIiIb", "nct", "dpp")
TARGET_BUILTIN(__builtin_amdgcn_update_dpp, "iiiIiIiIiIb", "nct", "dpp")
TARGET_BUILTIN(__builtin_amdgcn_s_dcache_wb, "v", "n", "gfx8-insts")
TARGET_BUILTIN(__builtin_amdgcn_perm, "UiUiUiUi", "nc", "gfx8-insts")

Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2182,10 +2182,10 @@ def err_covariant_return_incomplete : Error<
def err_covariant_return_type_different_qualifications : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (%1 has different qualifiers than %2)">;
def err_covariant_return_type_class_type_more_qualified : Error<
def err_covariant_return_type_class_type_not_same_or_less_qualified : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (class type %1 is more qualified than class "
"type %2">;
"the function it overrides (class type %1 does not have the same "
"cv-qualification as or less cv-qualification than class type %2)">;

// C++ implicit special member functions
def note_in_declaration_of_implicit_special_member : Note<
Expand Down Expand Up @@ -12499,7 +12499,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|unsafe invocation of span::data|"
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
"field %1 prone to unsafe buffer manipulation}0">,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def warn_unsafe_buffer_libc_call : Warning<
Expand Down
20 changes: 13 additions & 7 deletions clang/include/clang/Basic/FileManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ class FileManager : public RefCountedBase<FileManager> {
std::unique_ptr<FileSystemStatCache> StatCache;

std::error_code getStatValue(StringRef Path, llvm::vfs::Status &Status,
bool isFile,
std::unique_ptr<llvm::vfs::File> *F);
bool isFile, std::unique_ptr<llvm::vfs::File> *F,
bool IsText = true);

/// Add all ancestors of the given path (pointing to either a file
/// or a directory) as virtual directories.
Expand Down Expand Up @@ -230,7 +230,8 @@ class FileManager : public RefCountedBase<FileManager> {
/// the failure to find this file.
llvm::Expected<FileEntryRef> getFileRef(StringRef Filename,
bool OpenFile = false,
bool CacheFailure = true);
bool CacheFailure = true,
bool IsText = true);

/// Get the FileEntryRef for stdin, returning an error if stdin cannot be
/// read.
Expand Down Expand Up @@ -290,23 +291,28 @@ class FileManager : public RefCountedBase<FileManager> {

/// Open the specified file as a MemoryBuffer, returning a new
/// MemoryBuffer if successful, otherwise returning null.
/// The IsText parameter controls whether the file should be opened as a text
/// or binary file, and should be set to false if the file contents should be
/// treated as binary.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(FileEntryRef Entry, bool isVolatile = false,
bool RequiresNullTerminator = true,
std::optional<int64_t> MaybeLimit = std::nullopt);
std::optional<int64_t> MaybeLimit = std::nullopt,
bool IsText = true);
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(StringRef Filename, bool isVolatile = false,
bool RequiresNullTerminator = true,
std::optional<int64_t> MaybeLimit = std::nullopt) const {
std::optional<int64_t> MaybeLimit = std::nullopt,
bool IsText = true) const {
return getBufferForFileImpl(Filename,
/*FileSize=*/MaybeLimit.value_or(-1),
isVolatile, RequiresNullTerminator);
isVolatile, RequiresNullTerminator, IsText);
}

private:
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFileImpl(StringRef Filename, int64_t FileSize, bool isVolatile,
bool RequiresNullTerminator) const;
bool RequiresNullTerminator, bool IsText) const;

DirectoryEntry *&getRealDirEntry(const llvm::vfs::Status &Status);

Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Basic/FileSystemStatCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ class FileSystemStatCache {
/// success for directories (not files). On a successful file lookup, the
/// implementation can optionally fill in \p F with a valid \p File object and
/// the client guarantees that it will close it.
static std::error_code
get(StringRef Path, llvm::vfs::Status &Status, bool isFile,
std::unique_ptr<llvm::vfs::File> *F,
FileSystemStatCache *Cache, llvm::vfs::FileSystem &FS);
static std::error_code get(StringRef Path, llvm::vfs::Status &Status,
bool isFile, std::unique_ptr<llvm::vfs::File> *F,
FileSystemStatCache *Cache,
llvm::vfs::FileSystem &FS, bool IsText = true);

protected:
// FIXME: The pointer here is a non-owning/optional reference to the
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,14 @@ class LangOptions : public LangOptionsBase {
return ConvergentFunctions;
}

/// Return true if atomicrmw operations targeting allocations in private
/// memory are undefined.
bool threadPrivateMemoryAtomicsAreUndefined() const {
// Should be false for OpenMP.
// TODO: Should this be true for SYCL?
return OpenCL || CUDA;
}

/// Return the OpenCL C or C++ version as a VersionTuple.
VersionTuple getOpenCLVersionTuple() const;

Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/ParsedAttrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Support/Compiler.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Registry.h"
#include <climits>
Expand Down Expand Up @@ -175,4 +176,8 @@ const std::list<std::unique_ptr<ParsedAttrInfo>> &getAttributePluginInstances();

} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI Registry<clang::ParsedAttrInfo>;
} // namespace llvm

#endif // LLVM_CLANG_BASIC_PARSEDATTRINFO_H
45 changes: 45 additions & 0 deletions clang/include/clang/Basic/StackExhaustionHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//===--- StackExhaustionHandler.h - A utility for warning once when close to out
// of stack space -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Defines a utilitiy for warning once when close to out of stack space.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_BASIC_STACK_EXHAUSTION_HANDLER_H
#define LLVM_CLANG_BASIC_STACK_EXHAUSTION_HANDLER_H

#include "clang/Basic/Diagnostic.h"

namespace clang {
class StackExhaustionHandler {
public:
StackExhaustionHandler(DiagnosticsEngine &diags) : DiagsRef(diags) {}

/// Run some code with "sufficient" stack space. (Currently, at least 256K
/// is guaranteed). Produces a warning if we're low on stack space and
/// allocates more in that case. Use this in code that may recurse deeply to
/// avoid stack overflow.
void runWithSufficientStackSpace(SourceLocation Loc,
llvm::function_ref<void()> Fn);

/// Check to see if we're low on stack space and produce a warning if we're
/// low on stack space (Currently, at least 256Kis guaranteed).
void warnOnStackNearlyExhausted(SourceLocation Loc);

private:
/// Warn that the stack is nearly exhausted.
void warnStackExhausted(SourceLocation Loc);

DiagnosticsEngine &DiagsRef;
bool WarnedStackExhausted = false;
};
} // end namespace clang

#endif // LLVM_CLANG_BASIC_STACK_EXHAUSTION_HANDLER_H
12 changes: 5 additions & 7 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ enum class FloatModeKind {
struct TransferrableTargetInfo {
unsigned char PointerWidth, PointerAlign;
unsigned char BoolWidth, BoolAlign;
unsigned char ShortWidth, ShortAlign;
unsigned char IntWidth, IntAlign;
unsigned char HalfWidth, HalfAlign;
unsigned char BFloat16Width, BFloat16Align;
Expand Down Expand Up @@ -497,13 +498,10 @@ class TargetInfo : public TransferrableTargetInfo,
unsigned getCharWidth() const { return 8; } // FIXME
unsigned getCharAlign() const { return 8; } // FIXME

/// Return the size of 'signed short' and 'unsigned short' for this
/// target, in bits.
unsigned getShortWidth() const { return 16; } // FIXME

/// Return the alignment of 'signed short' and 'unsigned short' for
/// this target.
unsigned getShortAlign() const { return 16; } // FIXME
/// getShortWidth/Align - Return the size of 'signed short' and
/// 'unsigned short' for this target, in bits.
unsigned getShortWidth() const { return ShortWidth; }
unsigned getShortAlign() const { return ShortAlign; }

/// getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for
/// this target, in bits.
Expand Down
7 changes: 5 additions & 2 deletions clang/include/clang/Basic/arm_neon.td
Original file line number Diff line number Diff line change
Expand Up @@ -1968,13 +1968,16 @@ let TargetGuard = "v8.3a,neon" in {
def VCADDQ_ROT90 : SInst<"vcaddq_rot90", "QQQ", "f">;
def VCADDQ_ROT270 : SInst<"vcaddq_rot270", "QQQ", "f">;

defm VCMLA_F32 : VCMLA_ROTS<"f", "uint64x1_t", "uint64x2_t">;
defm VCMLA_F32 : VCMLA_ROTS<"f", "uint64x1_t", "uint64x2_t">;
}
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.3a,neon" in {
def VCADDQ_ROT90_FP64 : SInst<"vcaddq_rot90", "QQQ", "d">;
def VCADDQ_ROT270_FP64 : SInst<"vcaddq_rot270", "QQQ", "d">;

defm VCMLA_FP64 : VCMLA_ROTS<"d", "uint64x2_t", "uint64x2_t">;
def VCMLAQ_FP64 : SInst<"vcmlaq", "QQQQ", "d">;
def VCMLAQ_ROT90_FP64 : SInst<"vcmlaq_rot90", "QQQQ", "d">;
def VCMLAQ_ROT180_FP64 : SInst<"vcmlaq_rot180", "QQQQ", "d">;
def VCMLAQ_ROT270_FP64 : SInst<"vcmlaq_rot270", "QQQQ", "d">;
}

// V8.2-A BFloat intrinsics
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/arm_sve_sme_incl.td
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def EltTyBool16 : EltType<10>;
def EltTyBool32 : EltType<11>;
def EltTyBool64 : EltType<12>;
def EltTyBFloat16 : EltType<13>;
def EltTyMFloat8 : EltType<14>;

class MemEltType<int val> {
int Value = val;
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Driver/Distro.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class Distro {
UbuntuMantic,
UbuntuNoble,
UbuntuOracular,
UbuntuPlucky,
UnknownDistro
};

Expand Down Expand Up @@ -131,7 +132,7 @@ class Distro {
}

bool IsUbuntu() const {
return DistroVal >= UbuntuHardy && DistroVal <= UbuntuOracular;
return DistroVal >= UbuntuHardy && DistroVal <= UbuntuPlucky;
}

bool IsAlpineLinux() const { return DistroVal == AlpineLinux; }
Expand Down
15 changes: 11 additions & 4 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3454,7 +3454,8 @@ def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group<f_Group>,
def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group<f_Group>;
def fno_struct_path_tbaa : Flag<["-"], "fno-struct-path-tbaa">, Group<f_Group>;
def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group<f_Group>;
def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group<f_Group>;
def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group<f_Group>,
Visibility<[ClangOption, FlangOption]>;
def fno_pointer_tbaa : Flag<["-"], "fno-pointer-tbaa">, Group<f_Group>;
def fno_temp_file : Flag<["-"], "fno-temp-file">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, HelpText<
Expand All @@ -3470,7 +3471,8 @@ def fno_verbose_asm : Flag<["-"], "fno-verbose-asm">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoNegativeFlag<CodeGenOpts<"AsmVerbose">>;
def fno_working_directory : Flag<["-"], "fno-working-directory">, Group<f_Group>;
def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>;
def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>,
Visibility<[ClangOption, FlangOption]>;
def fobjc_arc : Flag<["-"], "fobjc-arc">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Synthesize retain and release calls for Objective-C pointers">;
Expand Down Expand Up @@ -3966,7 +3968,8 @@ defm strict_vtable_pointers : BoolFOption<"strict-vtable-pointers",
"Enable optimizations based on the strict rules for"
" overwriting polymorphic C++ objects">,
NegFlag<SetFalse>>;
def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group<f_Group>;
def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group<f_Group>,
Visibility<[ClangOption, FlangOption]>;
def fpointer_tbaa : Flag<["-"], "fpointer-tbaa">, Group<f_Group>;
def fdriver_only : Flag<["-"], "fdriver-only">, Flags<[NoXarchOption]>,
Visibility<[ClangOption, CLOption, DXCOption]>,
Expand Down Expand Up @@ -4235,7 +4238,7 @@ defm virtual_function_elimination : BoolFOption<"virtual-function-elimination",
NegFlag<SetFalse>, BothFlags<[], [ClangOption, CLOption]>>;

def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
Expand Down Expand Up @@ -5387,6 +5390,10 @@ def mno_lasx : Flag<["-"], "mno-lasx">, Group<m_loongarch_Features_Group>,
let Flags = [TargetSpecific] in {
def msimd_EQ : Joined<["-"], "msimd=">, Group<m_loongarch_Features_Group>,
HelpText<"Select the SIMD extension(s) to be enabled in LoongArch either 'none', 'lsx', 'lasx'.">;
def mfrecipe : Flag<["-"], "mfrecipe">, Group<m_loongarch_Features_Group>,
HelpText<"Enable frecipe.{s/d} and frsqrte.{s/d}">;
def mno_frecipe : Flag<["-"], "mno-frecipe">, Group<m_loongarch_Features_Group>,
HelpText<"Disable frecipe.{s/d} and frsqrte.{s/d}">;
def mannotate_tablejump : Flag<["-"], "mannotate-tablejump">, Group<m_loongarch_Features_Group>,
HelpText<"Enable annotate table jump instruction to correlate it with the jump table.">;
def mno_annotate_tablejump : Flag<["-"], "mno-annotate-tablejump">, Group<m_loongarch_Features_Group>,
Expand Down
25 changes: 25 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3938,6 +3938,29 @@ struct FormatStyle {
/// \version 14
bool RemoveBracesLLVM;

/// Remove empty lines within unwrapped lines.
/// \code
/// false: true:
///
/// int c vs. int c = a + b;
///
/// = a + b;
///
/// enum : unsigned vs. enum : unsigned {
/// AA = 0,
/// { BB
/// AA = 0, } myEnum;
/// BB
/// } myEnum;
///
/// while ( vs. while (true) {
/// }
/// true) {
/// }
/// \endcode
/// \version 20
bool RemoveEmptyLinesInUnwrappedLines;

/// Types of redundant parentheses to remove.
enum RemoveParenthesesStyle : int8_t {
/// Do not remove parentheses.
Expand Down Expand Up @@ -5232,6 +5255,8 @@ struct FormatStyle {
RawStringFormats == R.RawStringFormats &&
ReferenceAlignment == R.ReferenceAlignment &&
RemoveBracesLLVM == R.RemoveBracesLLVM &&
RemoveEmptyLinesInUnwrappedLines ==
R.RemoveEmptyLinesInUnwrappedLines &&
RemoveParentheses == R.RemoveParentheses &&
RemoveSemicolon == R.RemoveSemicolon &&
RequiresClausePosition == R.RequiresClausePosition &&
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Frontend/FrontendPluginRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H

#include "clang/Frontend/FrontendAction.h"
#include "clang/Support/Compiler.h"
#include "llvm/Support/Registry.h"

namespace clang {
Expand All @@ -23,4 +24,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginASTAction>;

} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI Registry<clang::PluginASTAction>;
} // namespace llvm

#endif // LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
5 changes: 5 additions & 0 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "clang/Lex/PPEmbedParameters.h"
#include "clang/Lex/Token.h"
#include "clang/Lex/TokenLexer.h"
#include "clang/Support/Compiler.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
Expand Down Expand Up @@ -3060,4 +3061,8 @@ using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>;

} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI Registry<clang::PragmaHandler>;
} // namespace llvm

#endif // LLVM_CLANG_LEX_PREPROCESSOR_H
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/MultiplexExternalSemaSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;

bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;

bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) override;

/// Ensures that the table of all visible declarations inside this
/// context is up to date.
void completeVisibleDeclsMap(const DeclContext *DC) override;
Expand Down
8 changes: 3 additions & 5 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "clang/Basic/PragmaKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/StackExhaustionHandler.h"
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Basic/TypeTraits.h"
Expand Down Expand Up @@ -546,9 +547,6 @@ class Sema final : public SemaBase {
/// Print out statistics about the semantic analysis.
void PrintStats() const;

/// Warn that the stack is nearly exhausted.
void warnStackExhausted(SourceLocation Loc);

/// Run some code with "sufficient" stack space. (Currently, at least 256K is
/// guaranteed). Produces a warning if we're low on stack space and allocates
/// more in that case. Use this in code that may recurse deeply (for example,
Expand Down Expand Up @@ -1183,7 +1181,7 @@ class Sema final : public SemaBase {
std::optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo;
bool WarnedDarwinSDKInfoMissing = false;

bool WarnedStackExhausted = false;
StackExhaustionHandler StackHandler;

Sema(const Sema &) = delete;
void operator=(const Sema &) = delete;
Expand Down Expand Up @@ -6755,7 +6753,7 @@ class Sema final : public SemaBase {

ExprResult BuildPredefinedExpr(SourceLocation Loc, PredefinedIdentKind IK);
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
ExprResult ActOnIntegerConstant(SourceLocation Loc, int64_t Val);

bool CheckLoopHintExpr(Expr *E, SourceLocation Loc, bool AllowZero);

Expand Down
57 changes: 57 additions & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,60 @@ class AttributeCommonInfo;
class IdentifierInfo;
class ParsedAttr;
class Scope;
class VarDecl;

using llvm::dxil::ResourceClass;

// FIXME: This can be hidden (as static function in SemaHLSL.cpp) once we no
// longer need to create builtin buffer types in HLSLExternalSemaSource.
bool CreateHLSLAttributedResourceType(
Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo = nullptr);

enum class BindingType : uint8_t { NotAssigned, Explicit, Implicit };

// DeclBindingInfo struct stores information about required/assigned resource
// binding onon a declaration for specific resource class.
struct DeclBindingInfo {
const VarDecl *Decl;
ResourceClass ResClass;
const HLSLResourceBindingAttr *Attr;
BindingType BindType;

DeclBindingInfo(const VarDecl *Decl, ResourceClass ResClass,
BindingType BindType = BindingType::NotAssigned,
const HLSLResourceBindingAttr *Attr = nullptr)
: Decl(Decl), ResClass(ResClass), Attr(Attr), BindType(BindType) {}

void setBindingAttribute(HLSLResourceBindingAttr *A, BindingType BT) {
assert(Attr == nullptr && BindType == BindingType::NotAssigned &&
"binding attribute already assigned");
Attr = A;
BindType = BT;
}
};

// ResourceBindings class stores information about all resource bindings
// in a shader. It is used for binding diagnostics and implicit binding
// assigments.
class ResourceBindings {
public:
DeclBindingInfo *addDeclBindingInfo(const VarDecl *VD,
ResourceClass ResClass);
DeclBindingInfo *getDeclBindingInfo(const VarDecl *VD,
ResourceClass ResClass);
bool hasBindingInfoForDecl(const VarDecl *VD) const;

private:
// List of all resource bindings required by the shader.
// A global declaration can have multiple bindings for different
// resource classes. They are all stored sequentially in this list.
// The DeclToBindingListIndex hashtable maps a declaration to the
// index of the first binding info in the list.
llvm::SmallVector<DeclBindingInfo> BindingsList;
llvm::DenseMap<const VarDecl *, unsigned> DeclToBindingListIndex;
};

class SemaHLSL : public SemaBase {
public:
SemaHLSL(Sema &S);
Expand All @@ -55,6 +102,7 @@ class SemaHLSL : public SemaBase {
mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLParamModifierAttr::Spelling Spelling);
void ActOnTopLevelFunction(FunctionDecl *FD);
void ActOnVariableDeclarator(VarDecl *VD);
void CheckEntryPoint(FunctionDecl *FD);
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
const HLSLAnnotationAttr *AnnotationAttr);
Expand Down Expand Up @@ -102,6 +150,15 @@ class SemaHLSL : public SemaBase {
llvm::DenseMap<const HLSLAttributedResourceType *,
HLSLAttributedResourceLocInfo>
LocsForHLSLAttributedResources;

// List of all resource bindings
ResourceBindings Bindings;

private:
void collectResourcesOnVarDecl(VarDecl *D);
void collectResourcesOnUserRecordDecl(const VarDecl *VD,
const RecordType *RT);
void processExplicitBindingsOnDecl(VarDecl *D);
};

} // namespace clang
Expand Down
15 changes: 14 additions & 1 deletion clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,13 @@ enum ASTRecordTypes {
/// Record code for Sema's vector of functions/blocks with effects to
/// be verified.
DECLS_WITH_EFFECTS_TO_VERIFY = 72,

/// Record code for updated specialization
UPDATE_SPECIALIZATION = 73,

CXX_ADDED_TEMPLATE_SPECIALIZATION = 74,

CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION = 75,
};

/// Record types used within a source manager block.
Expand Down Expand Up @@ -1149,7 +1156,7 @@ enum PredefinedTypeIDs {
///
/// Type IDs for non-predefined types will start at
/// NUM_PREDEF_TYPE_IDs.
const unsigned NUM_PREDEF_TYPE_IDS = 505;
const unsigned NUM_PREDEF_TYPE_IDS = 509;

// Ensure we do not overrun the predefined types we reserved
// in the enum PredefinedTypeIDs above.
Expand Down Expand Up @@ -1503,6 +1510,12 @@ enum DeclCode {
/// An ImplicitConceptSpecializationDecl record.
DECL_IMPLICIT_CONCEPT_SPECIALIZATION,

// A decls specilization record.
DECL_SPECIALIZATIONS,

// A decls specilization record.
DECL_PARTIAL_SPECIALIZATIONS,

DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION
};

Expand Down
50 changes: 45 additions & 5 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/OpenCLOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/StackExhaustionHandler.h"
#include "clang/Basic/Version.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/HeaderSearch.h"
Expand Down Expand Up @@ -352,6 +353,9 @@ class ASTIdentifierLookupTrait;
/// The on-disk hash table(s) used for DeclContext name lookup.
struct DeclContextLookupTable;

/// The on-disk hash table(s) used for specialization decls.
struct LazySpecializationInfoLookupTable;

} // namespace reader

} // namespace serialization
Expand Down Expand Up @@ -445,7 +449,7 @@ class ASTReader
DiagnosticsEngine &Diags;
// Sema has duplicate logic, but SemaObj can sometimes be null so ASTReader
// has its own version.
bool WarnedStackExhausted = false;
StackExhaustionHandler StackHandler;

/// The semantic analysis object that will be processing the
/// AST files and the translation unit that uses it.
Expand Down Expand Up @@ -630,20 +634,36 @@ class ASTReader
llvm::DenseMap<const DeclContext *,
serialization::reader::DeclContextLookupTable> Lookups;

using SpecLookupTableTy = llvm::DenseMap<const Decl *,
serialization::reader::LazySpecializationInfoLookupTable>;
/// Map from decls to specialized decls.
SpecLookupTableTy SpecializationsLookups;
/// Split partial specialization from specialization to speed up lookups.
SpecLookupTableTy PartialSpecializationsLookups;

bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, const Decl *D);
bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs);

// Updates for visible decls can occur for other contexts than just the
// TU, and when we read those update records, the actual context may not
// be available yet, so have this pending map using the ID as a key. It
// will be realized when the context is actually loaded.
struct PendingVisibleUpdate {
// will be realized when the data is actually loaded.
struct UpdateData {
ModuleFile *Mod;
const unsigned char *Data;
};
using DeclContextVisibleUpdates = SmallVector<PendingVisibleUpdate, 1>;
using DeclContextVisibleUpdates = SmallVector<UpdateData, 1>;

/// Updates to the visible declarations of declaration contexts that
/// haven't been loaded yet.
llvm::DenseMap<GlobalDeclID, DeclContextVisibleUpdates> PendingVisibleUpdates;

using SpecializationsUpdate = SmallVector<UpdateData, 1>;
using SpecializationsUpdateMap = llvm::DenseMap<GlobalDeclID, SpecializationsUpdate>;
SpecializationsUpdateMap PendingSpecializationsUpdates;
SpecializationsUpdateMap PendingPartialSpecializationsUpdates;

/// The set of C++ or Objective-C classes that have forward
/// declarations that have not yet been linked to their definitions.
llvm::SmallPtrSet<Decl *, 4> PendingDefinitions;
Expand Down Expand Up @@ -676,6 +696,11 @@ class ASTReader
llvm::BitstreamCursor &Cursor,
uint64_t Offset, GlobalDeclID ID);

bool ReadSpecializations(ModuleFile &M, llvm::BitstreamCursor &Cursor,
uint64_t Offset, Decl *D, bool IsPartial);
void AddSpecializations(const Decl *D, const unsigned char *Data,
ModuleFile &M, bool IsPartial);

/// A vector containing identifiers that have already been
/// loaded.
///
Expand Down Expand Up @@ -1378,6 +1403,14 @@ class ASTReader
const serialization::reader::DeclContextLookupTable *
getLoadedLookupTables(DeclContext *Primary) const;

/// Get the loaded specializations lookup tables for \p D,
/// if any.
serialization::reader::LazySpecializationInfoLookupTable *
getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial);

/// If we have any unloaded specialization for \p D
bool haveUnloadedSpecializations(const Decl *D) const;

private:
struct ImportedModule {
ModuleFile *Mod;
Expand Down Expand Up @@ -2035,6 +2068,12 @@ class ASTReader
unsigned BlockID,
uint64_t *StartOfBlockOffset = nullptr);

bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;

bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) override;

/// Finds all the visible declarations with a given name.
/// The current implementation of this method just loads the entire
/// lookup table as unmaterialized references.
Expand Down Expand Up @@ -2180,7 +2219,8 @@ class ASTReader
/// Report a diagnostic.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const;

void warnStackExhausted(SourceLocation Loc);
void runWithSufficientStackSpace(SourceLocation Loc,
llvm::function_ref<void()> Fn);

IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID);

Expand Down
17 changes: 17 additions & 0 deletions clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,13 @@ class ASTWriter : public ASTDeserializationListener,
/// Only meaningful for reduced BMI.
DeclUpdateMap DeclUpdatesFromGMF;

/// Mapping from decl templates and its new specialization in the
/// current TU.
using SpecializationUpdateMap =
llvm::MapVector<const NamedDecl *, SmallVector<const Decl *>>;
SpecializationUpdateMap SpecializationsUpdates;
SpecializationUpdateMap PartialSpecializationsUpdates;

using FirstLatestDeclMap = llvm::DenseMap<Decl *, Decl *>;

/// Map of first declarations from a chained PCH that point to the
Expand Down Expand Up @@ -577,6 +584,12 @@ class ASTWriter : public ASTDeserializationListener,

bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);

void GenerateSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial);
uint64_t WriteSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations, bool IsPartial);

void GenerateNameLookupTable(const DeclContext *DC,
llvm::SmallVectorImpl<char> &LookupTable);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context,
Expand All @@ -592,6 +605,7 @@ class ASTWriter : public ASTDeserializationListener,
void WriteDeclAndTypes(ASTContext &Context);
void PrepareWritingSpecialDecls(Sema &SemaRef);
void WriteSpecialDeclRecords(Sema &SemaRef);
void WriteSpecializationsUpdates(bool IsPartial);
void WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord);
void WriteDeclContextVisibleUpdate(const DeclContext *DC);
void WriteFPPragmaOptions(const FPOptionsOverride &Opts);
Expand Down Expand Up @@ -619,6 +633,9 @@ class ASTWriter : public ASTDeserializationListener,
unsigned DeclEnumAbbrev = 0;
unsigned DeclObjCIvarAbbrev = 0;
unsigned DeclCXXMethodAbbrev = 0;
unsigned DeclSpecializationsAbbrev = 0;
unsigned DeclPartialSpecializationsAbbrev = 0;

unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0;
unsigned DeclTemplateCXXMethodAbbrev = 0;
unsigned DeclMemberSpecializedCXXMethodAbbrev = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
#define LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H

#include "clang/Support/Compiler.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/Support/Registry.h"

Expand Down Expand Up @@ -42,4 +43,9 @@ using CompilationDatabasePluginRegistry =
} // namespace tooling
} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI
Registry<clang::tooling::CompilationDatabasePlugin>;
} // namespace llvm

#endif // LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
6 changes: 6 additions & 0 deletions clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
#define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H

#include "clang/Support/Compiler.h"
#include "clang/Tooling/Execution.h"
#include "llvm/Support/Registry.h"

Expand All @@ -20,4 +21,9 @@ using ToolExecutorPluginRegistry = llvm::Registry<ToolExecutorPlugin>;
} // namespace tooling
} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI
Registry<clang::tooling::ToolExecutorPlugin>;
} // namespace llvm

#endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
26 changes: 13 additions & 13 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,24 +362,24 @@ namespace clang {
template <typename TemplateParmDeclT>
Error importTemplateParameterDefaultArgument(const TemplateParmDeclT *D,
TemplateParmDeclT *ToD) {
Error Err = Error::success();
if (D->hasDefaultArgument()) {
if (D->defaultArgumentWasInherited()) {
auto *ToInheritedFrom = const_cast<TemplateParmDeclT *>(
importChecked(Err, D->getDefaultArgStorage().getInheritedFrom()));
if (Err)
return Err;
Expected<TemplateParmDeclT *> ToInheritedFromOrErr =
import(D->getDefaultArgStorage().getInheritedFrom());
if (!ToInheritedFromOrErr)
return ToInheritedFromOrErr.takeError();
TemplateParmDeclT *ToInheritedFrom = *ToInheritedFromOrErr;
if (!ToInheritedFrom->hasDefaultArgument()) {
// Resolve possible circular dependency between default value of the
// template argument and the template declaration.
const auto ToInheritedDefaultArg =
importChecked(Err, D->getDefaultArgStorage()
.getInheritedFrom()
->getDefaultArgument());
if (Err)
return Err;
Expected<TemplateArgumentLoc> ToInheritedDefaultArgOrErr =
import(D->getDefaultArgStorage()
.getInheritedFrom()
->getDefaultArgument());
if (!ToInheritedDefaultArgOrErr)
return ToInheritedDefaultArgOrErr.takeError();
ToInheritedFrom->setDefaultArgument(Importer.getToContext(),
ToInheritedDefaultArg);
*ToInheritedDefaultArgOrErr);
}
ToD->setInheritedDefaultArgument(ToD->getASTContext(),
ToInheritedFrom);
Expand All @@ -395,7 +395,7 @@ namespace clang {
*ToDefaultArgOrErr);
}
}
return Err;
return Error::success();
}

public:
Expand Down
113 changes: 67 additions & 46 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2371,9 +2371,9 @@ bool Compiler<Emitter>::VisitStringLiteral(const StringLiteral *E) {

template <class Emitter>
bool Compiler<Emitter>::VisitObjCStringLiteral(const ObjCStringLiteral *E) {
if (std::optional<unsigned> I = P.getOrCreateDummy(E))
return this->emitGetPtrGlobal(*I, E);
return false;
if (DiscardResult)
return true;
return this->emitDummyPtr(E, E);
}

template <class Emitter>
Expand Down Expand Up @@ -3445,11 +3445,8 @@ bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
assert(RD);
// If the definiton of the result type is incomplete, just return a dummy.
// If (and when) that is read from, we will fail, but not now.
if (!RD->isCompleteDefinition()) {
if (std::optional<unsigned> I = P.getOrCreateDummy(GuidDecl))
return this->emitGetPtrGlobal(*I, E);
return false;
}
if (!RD->isCompleteDefinition())
return this->emitDummyPtr(GuidDecl, E);

std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(GuidDecl);
if (!GlobalIndex)
Expand Down Expand Up @@ -3687,11 +3684,11 @@ bool Compiler<Emitter>::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
if (!E->isExpressibleAsConstantInitializer())
return this->discard(SubExpr) && this->emitInvalid(E);

assert(classifyPrim(E) == PT_Ptr);
if (std::optional<unsigned> I = P.getOrCreateDummy(E))
return this->emitGetPtrGlobal(*I, E);
if (DiscardResult)
return true;

return false;
assert(classifyPrim(E) == PT_Ptr);
return this->emitDummyPtr(E, E);
}

template <class Emitter>
Expand Down Expand Up @@ -4132,10 +4129,16 @@ template <class Emitter>
bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) {
LocalScope<Emitter> RootScope(this);

// If we won't destroy the toplevel scope, check for memory leaks first.
if (!DestroyToplevelScope) {
if (!this->emitCheckAllocations(E))
return false;
}

auto maybeDestroyLocals = [&]() -> bool {
if (DestroyToplevelScope)
return RootScope.destroyLocals();
return true;
return RootScope.destroyLocals() && this->emitCheckAllocations(E);
return this->emitCheckAllocations(E);
};

// Void expressions.
Expand Down Expand Up @@ -4171,8 +4174,7 @@ bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) {
return this->emitRetValue(E) && maybeDestroyLocals();
}

(void)maybeDestroyLocals();
return false;
return maybeDestroyLocals() && this->emitCheckAllocations(E) && false;
}

template <class Emitter>
Expand Down Expand Up @@ -4214,7 +4216,8 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD,
DeclScope<Emitter> LS(this, VD);
if (!this->visit(VD->getAnyInitializer()))
return false;
return this->emitRet(VarT.value_or(PT_Ptr), VD) && LS.destroyLocals();
return this->emitRet(VarT.value_or(PT_Ptr), VD) && LS.destroyLocals() &&
this->emitCheckAllocations(VD);
}

LocalScope<Emitter> VDScope(this, VD);
Expand Down Expand Up @@ -4260,7 +4263,7 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD,
return false;
}

return VDScope.destroyLocals();
return VDScope.destroyLocals() && this->emitCheckAllocations(VD);
}

template <class Emitter>
Expand Down Expand Up @@ -4477,15 +4480,9 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E,
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString ||
BuiltinID == Builtin::BI__builtin_ptrauth_sign_constant ||
BuiltinID == Builtin::BI__builtin_function_start) {
if (std::optional<unsigned> GlobalOffset = P.getOrCreateDummy(E)) {
if (!this->emitGetPtrGlobal(*GlobalOffset, E))
return false;

if (PrimType PT = classifyPrim(E); PT != PT_Ptr && isPtrType(PT))
return this->emitDecayPtr(PT_Ptr, PT, E);
if (DiscardResult)
return true;
}
return false;
return this->emitDummyPtr(E, E);
}

QualType ReturnType = E->getType();
Expand Down Expand Up @@ -4535,6 +4532,10 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete);
}
}
// Explicit calls to trivial destructors
if (const auto *DD = dyn_cast_if_present<CXXDestructorDecl>(FuncDecl);
DD && DD->isTrivial())
return true;

QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
std::optional<PrimType> T = classify(ReturnType);
Expand Down Expand Up @@ -5728,9 +5729,17 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
// We should already have a pointer when we get here.
return this->delegate(SubExpr);
case UO_Deref: // *x
if (DiscardResult)
if (DiscardResult) {
// assert(false);
return this->discard(SubExpr);
return this->visit(SubExpr);
}

if (!this->visit(SubExpr))
return false;
if (classifyPrim(SubExpr) == PT_Ptr)
return this->emitNarrowPtr(E);
return true;

case UO_Not: // ~x
if (!T)
return this->emitError(E);
Expand Down Expand Up @@ -6079,7 +6088,12 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {

if (VD->evaluateValue())
return revisit(VD);
return this->emitInvalidDeclRef(cast<DeclRefExpr>(E), E);

if (!D->getType()->isReferenceType())
return this->emitDummyPtr(D, E);

return this->emitInvalidDeclRef(cast<DeclRefExpr>(E),
/*InitializerFailed=*/true, E);
}
}
} else {
Expand All @@ -6090,23 +6104,7 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
}
}

if (std::optional<unsigned> I = P.getOrCreateDummy(D)) {
if (!this->emitGetPtrGlobal(*I, E))
return false;
if (E->getType()->isVoidType())
return true;
// Convert the dummy pointer to another pointer type if we have to.
if (PrimType PT = classifyPrim(E); PT != PT_Ptr) {
if (isPtrType(PT))
return this->emitDecayPtr(PT_Ptr, PT, E);
return false;
}
return true;
}

if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
return this->emitInvalidDeclRef(DRE, E);
return false;
return this->emitDummyPtr(D, E);
}

template <class Emitter>
Expand Down Expand Up @@ -6409,6 +6407,29 @@ bool Compiler<Emitter>::emitDestruction(const Descriptor *Desc,
return this->emitRecordDestruction(Desc->ElemRecord, Loc);
}

/// Create a dummy pointer for the given decl (or expr) and
/// push a pointer to it on the stack.
template <class Emitter>
bool Compiler<Emitter>::emitDummyPtr(const DeclTy &D, const Expr *E) {
assert(!DiscardResult && "Should've been checked before");

unsigned DummyID = P.getOrCreateDummy(D);

if (!this->emitGetPtrGlobal(DummyID, E))
return false;
if (E->getType()->isVoidType())
return true;

// Convert the dummy pointer to another pointer type if we have to.
if (PrimType PT = classifyPrim(E); PT != PT_Ptr) {
if (isPtrType(PT))
return this->emitDecayPtr(PT_Ptr, PT, E);
return false;
}

return true;
}

namespace clang {
namespace interp {

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
const BinaryOperator *E);
bool emitRecordDestruction(const Record *R, SourceInfo Loc);
bool emitDestruction(const Descriptor *Desc, SourceInfo Loc);
bool emitDummyPtr(const DeclTy &D, const Expr *E);
unsigned collectBaseOffset(const QualType BaseType,
const QualType DerivedType);
bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/ByteCode/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);

auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false,
/*DestroyToplevelScope=*/Kind ==
ConstantExprKind::ClassTemplateArgument);
/*DestroyToplevelScope=*/true);
if (Res.isInvalid()) {
C.cleanup();
Stk.clearTo(StackSizeBefore);
Expand Down
17 changes: 0 additions & 17 deletions clang/lib/AST/ByteCode/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,10 @@ bool EvalEmitter::fallthrough(const LabelTy &Label) {
return true;
}

static bool checkReturnState(InterpState &S) {
return S.maybeDiagnoseDanglingAllocations();
}

template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
if (!isActive())
return true;

if (!checkReturnState(S))
return false;

using T = typename PrimConv<OpType>::T;
EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
return true;
Expand All @@ -159,9 +152,6 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
return false;

if (!checkReturnState(S))
return false;

// Implicitly convert lvalue to rvalue, if requested.
if (ConvertResultToRValue) {
if (!Ptr.isZero() && !Ptr.isDereferencable())
Expand Down Expand Up @@ -194,16 +184,12 @@ template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {
if (!isActive())
return true;

if (!checkReturnState(S))
return false;
// Function pointers cannot be converted to rvalues.
EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>());
return true;
}

bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {
if (!checkReturnState(S))
return false;
EvalResult.setValid();
return true;
}
Expand All @@ -216,9 +202,6 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
return false;

if (!checkReturnState(S))
return false;

if (std::optional<APValue> APV =
Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) {
EvalResult.setValue(*APV);
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/AST/ByteCode/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,14 @@ template <unsigned Bits, bool Signed> class Integral final {
APSInt toAPSInt() const {
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
}
APSInt toAPSInt(unsigned NumBits) const {
APSInt toAPSInt(unsigned BitWidth) const { return APSInt(toAPInt(BitWidth)); }
APInt toAPInt(unsigned BitWidth) const {
if constexpr (Signed)
return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed);
return APInt(Bits, static_cast<uint64_t>(V), Signed)
.sextOrTrunc(BitWidth);
else
return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
return APInt(Bits, static_cast<uint64_t>(V), Signed)
.zextOrTrunc(BitWidth);
}
APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }

Expand Down
6 changes: 2 additions & 4 deletions clang/lib/AST/ByteCode/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ template <bool Signed> class IntegralAP final {

IntegralAP(APInt V) : V(V) {}
/// Arbitrary value for uninitialized variables.
IntegralAP() : IntegralAP(-1, 3) {}
IntegralAP() : IntegralAP(Signed ? -1 : 7, 3) {}

IntegralAP operator-() const { return IntegralAP(-V); }
IntegralAP operator-(const IntegralAP &Other) const {
Expand Down Expand Up @@ -112,9 +112,7 @@ template <bool Signed> class IntegralAP final {

template <unsigned Bits, bool InputSigned>
static IntegralAP from(Integral<Bits, InputSigned> I, unsigned BitWidth) {
APInt Copy = APInt(BitWidth, static_cast<uint64_t>(I), InputSigned);

return IntegralAP<Signed>(Copy);
return IntegralAP<Signed>(I.toAPInt(BitWidth));
}

static IntegralAP zero(int32_t BitWidth) {
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1040,7 +1040,6 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
return nullptr;
};

AllocType->dump();
if (const FunctionDecl *VirtualDelete =
getVirtualOperatorDelete(AllocType);
VirtualDelete &&
Expand Down
68 changes: 53 additions & 15 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1841,6 +1841,7 @@ bool Init(InterpState &S, CodePtr OpPC) {
assert(false);
return false;
}
Ptr.activate();
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
return true;
Expand All @@ -1852,6 +1853,7 @@ bool InitPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckInit(S, OpPC, Ptr))
return false;
Ptr.activate();
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
return true;
Expand All @@ -1863,27 +1865,48 @@ bool InitPop(InterpState &S, CodePtr OpPC) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
const T &Value = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
const Pointer &Ptr = S.Stk.peek<Pointer>();

if (Ptr.isUnknownSizeArray())
return false;
if (!CheckInit(S, OpPC, Ptr))

// In the unlikely event that we're initializing the first item of
// a non-array, skip the atIndex().
if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
return true;
}

const Pointer &ElemPtr = Ptr.atIndex(Idx);
if (!CheckInit(S, OpPC, ElemPtr))
return false;
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
ElemPtr.initialize();
new (&ElemPtr.deref<T>()) T(Value);
return true;
}

/// The same as InitElem, but pops the pointer as well.
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
const T &Value = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.isUnknownSizeArray())
return false;
if (!CheckInit(S, OpPC, Ptr))

// In the unlikely event that we're initializing the first item of
// a non-array, skip the atIndex().
if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
return true;
}

const Pointer &ElemPtr = Ptr.atIndex(Idx);
if (!CheckInit(S, OpPC, ElemPtr))
return false;
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
ElemPtr.initialize();
new (&ElemPtr.deref<T>()) T(Value);
return true;
}

Expand Down Expand Up @@ -1921,14 +1944,14 @@ inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {

template <class T, ArithOp Op>
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
const Pointer &Ptr) {
const Pointer &Ptr, bool IsPointerArith = false) {
// A zero offset does not change the pointer.
if (Offset.isZero()) {
S.Stk.push<Pointer>(Ptr);
return true;
}

if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
// The CheckNull will have emitted a note already, but we only
// abort in C++, since this is fine in C.
if (S.getLangOpts().CPlusPlus)
Expand Down Expand Up @@ -2040,14 +2063,16 @@ bool AddOffset(InterpState &S, CodePtr OpPC) {
Pointer Ptr = S.Stk.pop<Pointer>();
if (Ptr.isBlockPointer())
Ptr = Ptr.expand();
return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr,
/*IsPointerArith=*/true);
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
bool SubOffset(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();
return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr,
/*IsPointerArith=*/true);
}

template <ArithOp Op>
Expand All @@ -2067,7 +2092,7 @@ static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,

// Now the current Ptr again and a constant 1.
OneT One = OneT::from(1);
if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
if (!OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true))
return false;

// Store the new value.
Expand Down Expand Up @@ -2793,9 +2818,18 @@ inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
return false;
}

inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
const DeclRefExpr *DR) {
inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
bool InitializerFailed) {
assert(DR);

if (InitializerFailed) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
const auto *VD = cast<VarDecl>(DR->getDecl());
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at);
return false;
}

return CheckDeclRef(S, OpPC, DR);
}

Expand Down Expand Up @@ -2984,6 +3018,10 @@ static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
return true;
}

static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {
return S.maybeDiagnoseDanglingAllocations();
}

/// Check if the initializer and storage types of a placement-new expression
/// match.
bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
Expand Down
33 changes: 33 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,20 @@ static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_abs(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Val = peekToAPSInt(S.Stk, ArgT);
if (Val ==
APSInt(APInt::getSignedMinValue(Val.getBitWidth()), /*IsUnsigned=*/false))
return false;
if (Val.isNegative())
Val.negate();
pushInteger(S, Val, Call->getType());
return true;
}

static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
Expand Down Expand Up @@ -1239,6 +1253,10 @@ static bool interp__builtin_ia32_bextr(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
if (!Call->getArg(0)->getType()->isIntegerType() ||
!Call->getArg(1)->getType()->isIntegerType())
return false;

PrimType ValT = *S.Ctx.classify(Call->getArg(0));
PrimType IndexT = *S.Ctx.classify(Call->getArg(1));
APSInt Val = peekToAPSInt(S.Stk, ValT,
Expand Down Expand Up @@ -1317,6 +1335,10 @@ static bool interp__builtin_ia32_pdep(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
if (!Call->getArg(0)->getType()->isIntegerType() ||
!Call->getArg(1)->getType()->isIntegerType())
return false;

PrimType ValT = *S.Ctx.classify(Call->getArg(0));
PrimType MaskT = *S.Ctx.classify(Call->getArg(1));

Expand All @@ -1338,6 +1360,10 @@ static bool interp__builtin_ia32_pext(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
if (!Call->getArg(0)->getType()->isIntegerType() ||
!Call->getArg(1)->getType()->isIntegerType())
return false;

PrimType ValT = *S.Ctx.classify(Call->getArg(0));
PrimType MaskT = *S.Ctx.classify(Call->getArg(1));

Expand Down Expand Up @@ -1808,6 +1834,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_abs:
case Builtin::BI__builtin_labs:
case Builtin::BI__builtin_llabs:
if (!interp__builtin_abs(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_popcount:
case Builtin::BI__builtin_popcountl:
case Builtin::BI__builtin_popcountll:
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ def InvalidCast : Opcode {
}

def InvalidDeclRef : Opcode {
let Args = [ArgDeclRef];
let Args = [ArgDeclRef, ArgBool];
}

def SizelessVectorElementSize : Opcode;
Expand Down Expand Up @@ -836,3 +836,4 @@ def CheckNewTypeMismatchArray : Opcode {
}

def IsConstantContext: Opcode;
def CheckAllocations : Opcode;
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,

// Return the composite type.
APValue Result;
if (!Composite(getType(), *this, Result))
if (!Composite(ResultType, *this, Result))
return std::nullopt;
return Result;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
return std::nullopt;
}

std::optional<unsigned> Program::getOrCreateDummy(const DeclTy &D) {
unsigned Program::getOrCreateDummy(const DeclTy &D) {
assert(D);
// Dedup blocks since they are immutable and pointers cannot be compared.
if (auto It = DummyVariables.find(D.getOpaqueValue());
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Program.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Program final {
const Expr *Init = nullptr);

/// Returns or creates a dummy value for unknown declarations.
std::optional<unsigned> getOrCreateDummy(const DeclTy &D);
unsigned getOrCreateDummy(const DeclTy &D);

/// Creates a global and returns its index.
std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *Init);
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2512,7 +2512,8 @@ bool VarDecl::isUsableInConstantExpressions(const ASTContext &Context) const {
if (!DefVD->mightBeUsableInConstantExpressions(Context))
return false;
// ... and its initializer is a constant initializer.
if (Context.getLangOpts().CPlusPlus && !DefVD->hasConstantInitialization())
if ((Context.getLangOpts().CPlusPlus || getLangOpts().C23) &&
!DefVD->hasConstantInitialization())
return false;
// C++98 [expr.const]p1:
// An integral constant-expression can involve only [...] const variables
Expand Down Expand Up @@ -2619,8 +2620,11 @@ bool VarDecl::hasICEInitializer(const ASTContext &Context) const {
}

bool VarDecl::hasConstantInitialization() const {
// In C, all globals (and only globals) have constant initialization.
if (hasGlobalStorage() && !getASTContext().getLangOpts().CPlusPlus)
// In C, all globals and constexpr variables should have constant
// initialization. For constexpr variables in C check that initializer is a
// constant initializer because they can be used in constant expressions.
if (hasGlobalStorage() && !getASTContext().getLangOpts().CPlusPlus &&
!isConstexpr())
return true;

// In C++, it depends on whether the evaluation at the point of definition
Expand Down
Loading