27 changes: 19 additions & 8 deletions clang-tools-extra/clangd/InlayHints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Config.h"
#include "HeuristicResolver.h"
#include "ParsedAST.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
Expand Down Expand Up @@ -392,6 +393,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
// Don't show hints for variadic parameters.
size_t FixedParamCount = getFixedParamCount(Callee);
size_t ArgCount = std::min(FixedParamCount, Args.size());
auto Params = Callee->parameters();

NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);

Expand All @@ -402,12 +404,14 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {

for (size_t I = 0; I < ArgCount; ++I) {
StringRef Name = ParameterNames[I];
if (!shouldHint(Args[I], Name))
continue;
bool NameHint = shouldHintName(Args[I], Name);
bool ReferenceHint = shouldHintReference(Params[I]);

addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
InlayHintKind::ParameterHint, /*Prefix=*/"", Name,
/*Suffix=*/": ");
if (NameHint || ReferenceHint) {
addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
InlayHintKind::ParameterHint, ReferenceHint ? "&" : "",
NameHint ? Name : "", ": ");
}
}
}

Expand All @@ -434,12 +438,12 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
return WhatItIsSetting.equals_insensitive(ParamNames[0]);
}

bool shouldHint(const Expr *Arg, StringRef ParamName) {
bool shouldHintName(const Expr *Arg, StringRef ParamName) {
if (ParamName.empty())
return false;

// If the argument expression is a single name and it matches the
// parameter name exactly, omit the hint.
// parameter name exactly, omit the name hint.
if (ParamName == getSpelledIdentifier(Arg))
return false;

Expand All @@ -450,6 +454,13 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
return true;
}

bool shouldHintReference(const ParmVarDecl *Param) {
// If the parameter is a non-const reference type, print an inlay hint
auto Type = Param->getType();
return Type->isLValueReferenceType() &&
!Type.getNonReferenceType().isConstQualified();
}

// Checks if "E" is spelled in the main file and preceded by a C-style comment
// whose contents match ParamName (allowing for whitespace and an optional "="
// at the end.
Expand Down Expand Up @@ -563,7 +574,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
return Result;
}

// We pass HintSide rather than SourceLocation because we want to ensure
// We pass HintSide rather than SourceLocation because we want to ensure
// it is in the same file as the common file range.
void addInlayHint(SourceRange R, HintSide Side, InlayHintKind Kind,
llvm::StringRef Prefix, llvm::StringRef Label,
Expand Down
77 changes: 72 additions & 5 deletions clang-tools-extra/clangd/ParsedAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,69 @@ class ReplayPreamble : private PPCallbacks {
std::vector<syntax::Token> MainFileTokens;
};

// Filter for clang diagnostics groups enabled by CTOptions.Checks.
//
// These are check names like clang-diagnostics-unused.
// Note that unlike -Wunused, clang-diagnostics-unused does not imply
// subcategories like clang-diagnostics-unused-function.
//
// This is used to determine which diagnostics can be enabled by ExtraArgs in
// the clang-tidy configuration.
class TidyDiagnosticGroups {
// Whether all diagnostic groups are enabled by default.
// True if we've seen clang-diagnostic-*.
bool Default = false;
// Set of diag::Group whose enablement != Default.
// If Default is false, this is foo where we've seen clang-diagnostic-foo.
llvm::DenseSet<unsigned> Exceptions;

public:
TidyDiagnosticGroups(llvm::StringRef Checks) {
constexpr llvm::StringLiteral CDPrefix = "clang-diagnostic-";

llvm::StringRef Check;
while (!Checks.empty()) {
std::tie(Check, Checks) = Checks.split(',');
if (Check.empty())
continue;

bool Enable = !Check.consume_front("-");
bool Glob = Check.consume_back("*");
if (Glob) {
// Is this clang-diagnostic-*, or *, or so?
// (We ignore all other types of globs).
if (CDPrefix.startswith(Check)) {
Default = Enable;
Exceptions.clear();
}
continue;
}

// In "*,clang-diagnostic-foo", the latter is a no-op.
if (Default == Enable)
continue;
// The only non-glob entries we care about are clang-diagnostic-foo.
if (!Check.consume_front(CDPrefix))
continue;

if (auto Group = DiagnosticIDs::getGroupForWarningOption(Check))
Exceptions.insert(static_cast<unsigned>(*Group));
}
}

bool operator()(diag::Group GroupID) const {
return Exceptions.contains(static_cast<unsigned>(GroupID)) ? !Default
: Default;
}
};

// Find -W<group> and -Wno-<group> options in ExtraArgs and apply them to Diags.
//
// This is used to handle ExtraArgs in clang-tidy configuration.
// We don't use clang's standard handling of this as we want slightly different
// behavior (e.g. we want to exclude these from -Wno-error).
void applyWarningOptions(llvm::ArrayRef<std::string> ExtraArgs,
llvm::function_ref<bool(diag::Group)> EnabledGroups,
DiagnosticsEngine &Diags) {
for (llvm::StringRef Group : ExtraArgs) {
// Only handle args that are of the form -W[no-]<group>.
Expand All @@ -259,6 +316,9 @@ void applyWarningOptions(llvm::ArrayRef<std::string> ExtraArgs,
if (Enable) {
if (Diags.getDiagnosticLevel(ID, SourceLocation()) <
DiagnosticsEngine::Warning) {
auto Group = DiagnosticIDs::getGroupForDiag(ID);
if (!Group || !EnabledGroups(*Group))
continue;
Diags.setSeverity(ID, diag::Severity::Warning, SourceLocation());
if (Diags.getWarningsAsErrors())
NeedsWerrorExclusion = true;
Expand Down Expand Up @@ -354,18 +414,25 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
// - ExtraArgs: ["-Wfoo"] causes clang to produce the warnings
// - Checks: "clang-diagnostic-foo" prevents clang-tidy filtering them out
//
// We treat these as clang warnings, so the Checks part is not relevant.
// We must enable the warnings specified in ExtraArgs.
// In clang-tidy, diagnostics are emitted if they pass both checks.
// When groups contain subgroups, -Wparent includes the child, but
// clang-diagnostic-parent does not.
//
// We *don't* want to change the compile command directly. this can have
// We *don't* want to change the compile command directly. This can have
// too many unexpected effects: breaking the command, interactions with
// -- and -Werror, etc. Besides, we've already parsed the command.
// Instead we parse the -W<group> flags and handle them directly.
//
// Similarly, we don't want to use Checks to filter clang diagnostics after
// they are generated, as this spreads clang-tidy emulation everywhere.
// Instead, we just use these to filter which extra diagnostics we enable.
auto &Diags = Clang->getDiagnostics();
TidyDiagnosticGroups TidyGroups(ClangTidyOpts.Checks ? *ClangTidyOpts.Checks
: llvm::StringRef());
if (ClangTidyOpts.ExtraArgsBefore)
applyWarningOptions(*ClangTidyOpts.ExtraArgsBefore, Diags);
applyWarningOptions(*ClangTidyOpts.ExtraArgsBefore, TidyGroups, Diags);
if (ClangTidyOpts.ExtraArgs)
applyWarningOptions(*ClangTidyOpts.ExtraArgs, Diags);
applyWarningOptions(*ClangTidyOpts.ExtraArgs, TidyGroups, Diags);
} else {
// Skips some analysis.
Clang->getDiagnosticOpts().IgnoreWarnings = true;
Expand Down
9 changes: 8 additions & 1 deletion clang-tools-extra/clangd/Protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "support/Logger.h"
#include "clang/Basic/LLVM.h"
#include "clang/Index/IndexSymbol.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/JSON.h"
Expand Down Expand Up @@ -1318,7 +1319,7 @@ bool fromJSON(const llvm::json::Value &Params, InlayHintsParams &R,
return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
}

llvm::json::Value toJSON(InlayHintKind K) {
static llvm::StringLiteral toString(InlayHintKind K) {
switch (K) {
case InlayHintKind::ParameterHint:
return "parameter";
Expand All @@ -1330,6 +1331,8 @@ llvm::json::Value toJSON(InlayHintKind K) {
llvm_unreachable("Unknown clang.clangd.InlayHintKind");
}

llvm::json::Value toJSON(InlayHintKind K) { return toString(K); }

llvm::json::Value toJSON(const InlayHint &H) {
return llvm::json::Object{{"position", H.position},
{"range", H.range},
Expand All @@ -1345,6 +1348,10 @@ bool operator<(const InlayHint &A, const InlayHint &B) {
std::tie(B.position, B.range, B.kind, B.label);
}

llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) {
return OS << toString(Kind);
}

static const char *toString(OffsetEncoding OE) {
switch (OE) {
case OffsetEncoding::UTF8:
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/Protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,7 @@ struct InlayHint {
llvm::json::Value toJSON(const InlayHint &);
bool operator==(const InlayHint &, const InlayHint &);
bool operator<(const InlayHint &, const InlayHint &);
llvm::raw_ostream &operator<<(llvm::raw_ostream &, InlayHintKind);

struct ReferenceContext {
/// Include the declaration of the current symbol.
Expand Down
10 changes: 10 additions & 0 deletions clang-tools-extra/clangd/Selection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "AST.h"
#include "support/Logger.h"
#include "support/Trace.h"
#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
Expand Down Expand Up @@ -709,6 +710,15 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
bool TraversePseudoObjectExpr(PseudoObjectExpr *E) {
return traverseNode(E, [&] { return TraverseStmt(E->getSyntacticForm()); });
}
bool TraverseTypeConstraint(const TypeConstraint *C) {
if (auto *E = C->getImmediatelyDeclaredConstraint()) {
// Technically this expression is 'implicit' and not traversed by the RAV.
// However, the range is correct, so we visit expression to avoid adding
// an extra kind to 'DynTypeNode' that hold 'TypeConstraint'.
return TraverseStmt(E);
}
return Base::TraverseTypeConstraint(C);
}

private:
using Base = RecursiveASTVisitor<SelectionVisitor>;
Expand Down
25 changes: 18 additions & 7 deletions clang-tools-extra/clangd/tool/Check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
#include "Config.h"
#include "GlobalCompilationDatabase.h"
#include "Hover.h"
#include "InlayHints.h"
#include "ParsedAST.h"
#include "Preamble.h"
#include "Protocol.h"
#include "SourceCode.h"
#include "XRefs.h"
#include "index/CanonicalIncludes.h"
Expand Down Expand Up @@ -190,10 +192,19 @@ class Checker {
return true;
}

// Build Inlay Hints for the entire AST or the specified range
void buildInlayHints(llvm::Optional<Range> LineRange) {
log("Building inlay hints");
auto Hints = inlayHints(*AST, LineRange);

for (const auto &Hint : Hints) {
vlog(" {0} {1} {2}", Hint.kind, Hint.position, Hint.label);
}
}

// Run AST-based features at each token in the file.
void testLocationFeatures(
llvm::function_ref<bool(const Position &)> ShouldCheckLine,
const bool EnableCodeCompletion) {
void testLocationFeatures(llvm::Optional<Range> LineRange,
const bool EnableCodeCompletion) {
trace::Span Trace("testLocationFeatures");
log("Testing features at each token (may be slow in large files)");
auto &SM = AST->getSourceManager();
Expand All @@ -207,7 +218,7 @@ class Checker {
unsigned End = Start + Tok.length();
Position Pos = offsetToPosition(Inputs.Contents, Start);

if (!ShouldCheckLine(Pos))
if (LineRange && !LineRange->contains(Pos))
continue;

trace::Span Trace("Token");
Expand Down Expand Up @@ -254,8 +265,7 @@ class Checker {

} // namespace

bool check(llvm::StringRef File,
llvm::function_ref<bool(const Position &)> ShouldCheckLine,
bool check(llvm::StringRef File, llvm::Optional<Range> LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion) {
llvm::SmallString<0> FakeFile;
Expand Down Expand Up @@ -284,7 +294,8 @@ bool check(llvm::StringRef File,
if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
!C.buildAST())
return false;
C.testLocationFeatures(ShouldCheckLine, EnableCodeCompletion);
C.buildInlayHints(LineRange);
C.testLocationFeatures(LineRange, EnableCodeCompletion);

log("All checks completed, {0} errors", C.ErrCount);
return C.ErrCount == 0;
Expand Down
19 changes: 9 additions & 10 deletions clang-tools-extra/clangd/tool/ClangdMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ namespace clang {
namespace clangd {

// Implemented in Check.cpp.
bool check(const llvm::StringRef File,
llvm::function_ref<bool(const Position &)> ShouldCheckLine,
bool check(const llvm::StringRef File, llvm::Optional<Range> LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion);

Expand Down Expand Up @@ -955,8 +954,9 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
return 1;
}
log("Entering check mode (no LSP server)");
uint32_t Begin = 0, End = std::numeric_limits<uint32_t>::max();
llvm::Optional<Range> CheckLineRange;
if (!CheckFileLines.empty()) {
uint32_t Begin = 0, End = std::numeric_limits<uint32_t>::max();
StringRef RangeStr(CheckFileLines);
bool ParseError = RangeStr.consumeInteger(0, Begin);
if (RangeStr.empty()) {
Expand All @@ -965,19 +965,18 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
ParseError |= !RangeStr.consume_front("-");
ParseError |= RangeStr.consumeInteger(0, End);
}
if (ParseError || !RangeStr.empty()) {
elog("Invalid --check-line specified. Use Begin-End format, e.g. 3-17");
if (ParseError || !RangeStr.empty() || Begin <= 0 || End < Begin) {
elog(
"Invalid --check-lines specified. Use Begin-End format, e.g. 3-17");
return 1;
}
CheckLineRange = Range{Position{static_cast<int>(Begin - 1), 0},
Position{static_cast<int>(End), 0}};
}
auto ShouldCheckLine = [&](const Position &Pos) {
uint32_t Line = Pos.line + 1; // Position::line is 0-based.
return Line >= Begin && Line <= End;
};
// For now code completion is enabled any time the range is limited via
// --check-lines. If it turns out to be to slow, we can introduce a
// dedicated flag for that instead.
return check(Path, ShouldCheckLine, TFS, Opts,
return check(Path, CheckLineRange, TFS, Opts,
/*EnableCodeCompletion=*/!CheckFileLines.empty())
? 0
: static_cast<int>(ErrorResultCode::CheckFailed);
Expand Down
62 changes: 45 additions & 17 deletions clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,13 +517,16 @@ TEST(DiagnosticTest, ClangTidyWarningAsError) {
diagSeverity(DiagnosticsEngine::Error)))));
}

TidyProvider addClangArgs(std::vector<llvm::StringRef> ExtraArgs) {
return [ExtraArgs = std::move(ExtraArgs)](tidy::ClangTidyOptions &Opts,
llvm::StringRef) {
TidyProvider addClangArgs(std::vector<llvm::StringRef> ExtraArgs,
llvm::StringRef Checks) {
return [ExtraArgs = std::move(ExtraArgs), Checks = Checks.str()](
tidy::ClangTidyOptions &Opts, llvm::StringRef) {
if (!Opts.ExtraArgs)
Opts.ExtraArgs.emplace();
for (llvm::StringRef Arg : ExtraArgs)
Opts.ExtraArgs->emplace_back(Arg);
if (!Checks.empty())
Opts.Checks = Checks;
};
}

Expand All @@ -541,53 +544,78 @@ TEST(DiagnosticTest, ClangTidyEnablesClangWarning) {
// Check the -Wunused warning isn't initially on.
EXPECT_THAT(*TU.build().getDiagnostics(), IsEmpty());

// We enable warnings based on clang-tidy extra args.
TU.ClangTidyProvider = addClangArgs({"-Wunused"});
// We enable warnings based on clang-tidy extra args, if the matching
// clang-diagnostic- is there.
TU.ClangTidyProvider =
addClangArgs({"-Wunused"}, "clang-diagnostic-unused-function");
EXPECT_THAT(*TU.build().getDiagnostics(), ElementsAre(UnusedFooWarning));

// clang-diagnostic-* is acceptable
TU.ClangTidyProvider = addClangArgs({"-Wunused"}, "clang-diagnostic-*");
EXPECT_THAT(*TU.build().getDiagnostics(), ElementsAre(UnusedFooWarning));
// And plain * (may turn on other checks too).
TU.ClangTidyProvider = addClangArgs({"-Wunused"}, "*");
EXPECT_THAT(*TU.build().getDiagnostics(), Contains(UnusedFooWarning));
// And we can explicitly exclude a category too.
TU.ClangTidyProvider = addClangArgs(
{"-Wunused"}, "clang-diagnostic-*,-clang-diagnostic-unused-function");
EXPECT_THAT(*TU.build().getDiagnostics(), IsEmpty());

// Without the exact check specified, the warnings are not enabled.
TU.ClangTidyProvider = addClangArgs({"-Wunused"}, "clang-diagnostic-unused");
EXPECT_THAT(*TU.build().getDiagnostics(), IsEmpty());

// But we don't respect other args.
TU.ClangTidyProvider = addClangArgs({"-Wunused", "-Dfoo=bar"});
// We don't respect other args.
TU.ClangTidyProvider = addClangArgs({"-Wunused", "-Dfoo=bar"},
"clang-diagnostic-unused-function");
EXPECT_THAT(*TU.build().getDiagnostics(), ElementsAre(UnusedFooWarning))
<< "Not unused function 'bar'!";

// -Werror doesn't apply to warnings enabled by clang-tidy extra args.
TU.ExtraArgs = {"-Werror"};
TU.ClangTidyProvider = addClangArgs({"-Wunused"});
TU.ClangTidyProvider =
addClangArgs({"-Wunused"}, "clang-diagnostic-unused-function");
EXPECT_THAT(*TU.build().getDiagnostics(),
ElementsAre(diagSeverity(DiagnosticsEngine::Warning)));

// But clang-tidy extra args won't *downgrade* errors to warnings either.
TU.ExtraArgs = {"-Wunused", "-Werror"};
TU.ClangTidyProvider = addClangArgs({"-Wunused"});
TU.ClangTidyProvider =
addClangArgs({"-Wunused"}, "clang-diagnostic-unused-function");
EXPECT_THAT(*TU.build().getDiagnostics(),
ElementsAre(diagSeverity(DiagnosticsEngine::Error)));

// FIXME: we're erroneously downgrading the whole group, this should be Error.
TU.ExtraArgs = {"-Wunused-function", "-Werror"};
TU.ClangTidyProvider = addClangArgs({"-Wunused"});
TU.ClangTidyProvider =
addClangArgs({"-Wunused"}, "clang-diagnostic-unused-label");
EXPECT_THAT(*TU.build().getDiagnostics(),
ElementsAre(diagSeverity(DiagnosticsEngine::Warning)));

// This looks silly, but it's the typical result if a warning is enabled by a
// high-level .clang-tidy file and disabled by a low-level one.
TU.ExtraArgs = {};
TU.ClangTidyProvider = addClangArgs({"-Wunused", "-Wno-unused"});
TU.ClangTidyProvider = addClangArgs({"-Wunused", "-Wno-unused"},
"clang-diagnostic-unused-function");
EXPECT_THAT(*TU.build().getDiagnostics(), IsEmpty());

// Overriding only works in the proper order.
TU.ClangTidyProvider = addClangArgs({"-Wno-unused", "-Wunused"});
TU.ClangTidyProvider =
addClangArgs({"-Wunused"}, {"clang-diagnostic-unused-function"});
EXPECT_THAT(*TU.build().getDiagnostics(), SizeIs(1));

// More specific vs less-specific: match clang behavior
TU.ClangTidyProvider = addClangArgs({"-Wunused", "-Wno-unused-function"});
TU.ClangTidyProvider = addClangArgs({"-Wunused", "-Wno-unused-function"},
{"clang-diagnostic-unused-function"});
EXPECT_THAT(*TU.build().getDiagnostics(), IsEmpty());
TU.ClangTidyProvider = addClangArgs({"-Wunused-function", "-Wno-unused"});
TU.ClangTidyProvider = addClangArgs({"-Wunused-function", "-Wno-unused"},
{"clang-diagnostic-unused-function"});
EXPECT_THAT(*TU.build().getDiagnostics(), IsEmpty());

// We do allow clang-tidy config to disable warnings from the compile command.
// It's unclear this is ideal, but it's hard to avoid.
// We do allow clang-tidy config to disable warnings from the compile
// command. It's unclear this is ideal, but it's hard to avoid.
TU.ExtraArgs = {"-Wunused"};
TU.ClangTidyProvider = addClangArgs({"-Wno-unused"});
TU.ClangTidyProvider = addClangArgs({"-Wno-unused"}, {});
EXPECT_THAT(*TU.build().getDiagnostics(), IsEmpty());
}

Expand Down
8 changes: 8 additions & 0 deletions clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ TEST(IncludeCleaner, ReferencedLocations) {
template <template <typename> class T> class X {};
X<A> x;
)cpp"},
{R"cpp(
namespace ns { template<typename T> class A {}; }
namespace absl {using ns::^A;}
)cpp",
R"cpp(
template <template <typename> class T> class X {};
X<absl::A> x;
)cpp"},
{R"cpp(
namespace ns { template<typename T> struct ^A { ^A(T); }; }
using ns::^A;
Expand Down
107 changes: 107 additions & 0 deletions clang-tools-extra/clangd/unittests/InlayHintTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,38 @@ TEST(ParameterHints, NoName) {
)cpp");
}

TEST(ParameterHints, NoNameConstReference) {
// No hint for anonymous const l-value ref parameter.
assertParameterHints(R"cpp(
void foo(const int&);
void bar() {
foo(42);
}
)cpp");
}

TEST(ParameterHints, NoNameReference) {
// Reference hint for anonymous l-value ref parameter.
assertParameterHints(R"cpp(
void foo(int&);
void bar() {
int i;
foo($param[[i]]);
}
)cpp",
ExpectedHint{"&: ", "param"});
}

TEST(ParameterHints, NoNameRValueReference) {
// No reference hint for anonymous r-value ref parameter.
assertParameterHints(R"cpp(
void foo(int&&);
void bar() {
foo(42);
}
)cpp");
}

TEST(ParameterHints, NameInDefinition) {
// Parameter name picked up from definition if necessary.
assertParameterHints(R"cpp(
Expand All @@ -162,6 +194,66 @@ TEST(ParameterHints, NameMismatch) {
ExpectedHint{"good: ", "good"});
}

TEST(ParameterHints, NameConstReference) {
// Only name hint for const l-value ref parameter.
assertParameterHints(R"cpp(
void foo(const int& param);
void bar() {
foo($param[[42]]);
}
)cpp",
ExpectedHint{"param: ", "param"});
}

TEST(ParameterHints, NameTypeAliasConstReference) {
// Only name hint for const l-value ref parameter via type alias.
assertParameterHints(R"cpp(
using alias = const int&;
void foo(alias param);
void bar() {
int i;
foo($param[[i]]);
}
)cpp",
ExpectedHint{"param: ", "param"});
}

TEST(ParameterHints, NameReference) {
// Reference and name hint for l-value ref parameter.
assertParameterHints(R"cpp(
void foo(int& param);
void bar() {
int i;
foo($param[[i]]);
}
)cpp",
ExpectedHint{"&param: ", "param"});
}

TEST(ParameterHints, NameTypeAliasReference) {
// Reference and name hint for l-value ref parameter via type alias.
assertParameterHints(R"cpp(
using alias = int&;
void foo(alias param);
void bar() {
int i;
foo($param[[i]]);
}
)cpp",
ExpectedHint{"&param: ", "param"});
}

TEST(ParameterHints, NameRValueReference) {
// Only name hint for r-value ref parameter.
assertParameterHints(R"cpp(
void foo(int&& param);
void bar() {
foo($param[[42]]);
}
)cpp",
ExpectedHint{"param: ", "param"});
}

TEST(ParameterHints, Operator) {
// No hint for operator call with operator syntax.
assertParameterHints(R"cpp(
Expand Down Expand Up @@ -301,6 +393,21 @@ TEST(ParameterHints, ArgMatchesParam) {
ExpectedHint{"param: ", "param"});
}

TEST(ParameterHints, ArgMatchesParamReference) {
assertParameterHints(R"cpp(
void foo(int& param);
void foo2(const int& param);
void bar() {
int param;
// show reference hint on mutable reference
foo($param[[param]]);
// but not on const reference
foo2(param);
}
)cpp",
ExpectedHint{"&: ", "param"});
}

TEST(ParameterHints, LeadingUnderscore) {
assertParameterHints(R"cpp(
void foo(int p1, int _p2, int __p3);
Expand Down
13 changes: 13 additions & 0 deletions clang-tools-extra/clangd/unittests/XRefsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2085,6 +2085,19 @@ TEST(FindReferences, ConceptsWithinAST) {
checkFindRefs(Code);
}

TEST(FindReferences, ConceptReq) {
constexpr llvm::StringLiteral Code = R"cpp(
template <class T>
concept $def[[IsSmal^l]] = sizeof(T) <= 8;
template <class T>
concept IsSmallPtr = requires(T x) {
{ *x } -> [[IsSmal^l]];
};
)cpp";
checkFindRefs(Code);
}

TEST(FindReferences, RequiresExprParameters) {
constexpr llvm::StringLiteral Code = R"cpp(
template <class T>
Expand Down
24 changes: 12 additions & 12 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ New check aliases
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^

- Fixed nonsensical suggestion of :doc:`altera-struct-pack-align
<clang-tidy/checks/altera-struct-pack-align>` check for empty structs.

- Fixed some false positives in :doc:`bugprone-infinite-loop
<clang-tidy/checks/bugprone-infinite-loop>` involving dependent expressions.

- Fixed a crash in :doc:`bugprone-sizeof-expression
<clang-tidy/checks/bugprone-sizeof-expression>` when `sizeof(...)` is
compared against a `__int128_t`.
Expand All @@ -158,26 +164,20 @@ Changes in existing checks
<clang-tidy/checks/misc-redundant-expression>` involving assignments in
conditions. This fixes `Issue 35853 <https://github.com/llvm/llvm-project/issues/35853>`_.

- Fixed a crash in :doc:`readability-const-return-type
<clang-tidy/checks/readability-const-return-type>` when a pure virtual function
overrided has a const return type. Removed the fix for a virtual function.

- Fixed a false positive in :doc:`readability-non-const-parameter
<clang-tidy/checks/readability-non-const-parameter>` when the parameter is
referenced by an lvalue.

- Improved :doc:`performance-inefficient-vector-operation
<clang-tidy/checks/performance-inefficient-vector-operation>` to work when
the vector is a member of a structure.

- Fixed nonsensical suggestion of :doc:`altera-struct-pack-align
<clang-tidy/checks/altera-struct-pack-align>` check for empty structs.
- Fixed a crash in :doc:`readability-const-return-type
<clang-tidy/checks/readability-const-return-type>` when a pure virtual function
overrided has a const return type. Removed the fix for a virtual function.

- Fixed incorrect suggestions for :doc:`readability-container-size-empty
<clang-tidy/checks/readability-container-size-empty>` when smart pointers are involved.

- Fixed some false positives in :doc:`bugprone-infinite-loop
<clang-tidy/checks/bugprone-infinite-loop>` involving dependent expressions.
- Fixed a false positive in :doc:`readability-non-const-parameter
<clang-tidy/checks/readability-non-const-parameter>` when the parameter is
referenced by an lvalue.

Removed checks
^^^^^^^^^^^^^^
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/include-cleaner/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_subdirectory(lib)
if(CLANG_INCLUDE_TESTS)
add_subdirectory(test)
add_subdirectory(unittests)
endif()
Empty file.
47 changes: 47 additions & 0 deletions clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===--- AnalysisInternal.h - Analysis building blocks ------------- 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
//
//===----------------------------------------------------------------------===//
//
// This file provides smaller, testable pieces of the used-header analysis.
// We find the headers by chaining together several mappings.
//
// AST => AST node => Symbol => Location => Header
// /
// Macro expansion =>
//
// The individual steps are declared here.
// (AST => AST Node => Symbol is one API to avoid materializing DynTypedNodes).
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_INCLUDE_CLEANER_ANALYSISINTERNAL_H
#define CLANG_INCLUDE_CLEANER_ANALYSISINTERNAL_H

#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/STLFunctionalExtras.h"

namespace clang {
class Decl;
class NamedDecl;
namespace include_cleaner {

/// Traverses part of the AST from \p Root, finding uses of symbols.
///
/// Each use is reported to the callback:
/// - the SourceLocation describes where the symbol was used. This is usually
/// the primary location of the AST node found under Root.
/// - the NamedDecl is the symbol referenced. It is canonical, rather than e.g.
/// the redecl actually found by lookup.
///
/// walkAST is typically called once per top-level declaration in the file
/// being analyzed, in order to find all references within it.
void walkAST(Decl &Root, llvm::function_ref<void(SourceLocation, NamedDecl &)>);

} // namespace include_cleaner
} // namespace clang

#endif
10 changes: 10 additions & 0 deletions clang-tools-extra/include-cleaner/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
set(LLVM_LINK_COMPONENTS Support)

add_clang_library(clangIncludeCleaner
WalkAST.cpp

LINK_LIBS
clangBasic
clangAST
)

47 changes: 47 additions & 0 deletions clang-tools-extra/include-cleaner/lib/WalkAST.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===--- WalkAST.cpp - Find declaration references in the AST -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "AnalysisInternal.h"
#include "clang/AST/RecursiveASTVisitor.h"

namespace clang {
namespace include_cleaner {
namespace {
using DeclCallback = llvm::function_ref<void(SourceLocation, NamedDecl &)>;

class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
DeclCallback Callback;

void report(SourceLocation Loc, NamedDecl *ND) {
if (!ND || Loc.isInvalid())
return;
Callback(Loc, *cast<NamedDecl>(ND->getCanonicalDecl()));
}

public:
ASTWalker(DeclCallback Callback) : Callback(Callback) {}

bool VisitTagTypeLoc(TagTypeLoc TTL) {
report(TTL.getNameLoc(), TTL.getDecl());
return true;
}

bool VisitDeclRefExpr(DeclRefExpr *DRE) {
report(DRE->getLocation(), DRE->getFoundDecl());
return true;
}
};

} // namespace

void walkAST(Decl &Root, DeclCallback Callback) {
ASTWalker(Callback).TraverseDecl(&Root);
}

} // namespace include_cleaner
} // namespace clang
25 changes: 25 additions & 0 deletions clang-tools-extra/include-cleaner/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
set(CLANG_INCLUDE_CLEANER_TEST_DEPS
ClangIncludeCleanerTests
)

foreach (dep FileCheck not count)
if(TARGET ${dep})
list(APPEND CLANG_INCLUDE_CLEANER_TEST_DEPS ${dep})
endif()
endforeach()

configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py
MAIN_CONFIG
${CMAKE_CURRENT_BINARY_DIR}/lit.cfg.py)

configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py
MAIN_CONFIG
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.cfg.py)

add_lit_testsuite(check-clang-include-cleaner "Running the clang-include-cleaner regression tests"
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${CLANG_INCLUDE_CLEANER_TEST_DEPS})
18 changes: 18 additions & 0 deletions clang-tools-extra/include-cleaner/test/Unit/lit.cfg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import lit.formats
config.name = "clangIncludeCleaner Unit Tests"
config.test_format = lit.formats.GoogleTest('.', 'Tests')
config.test_source_root = config.clang_include_cleaner_binary_dir + "/unittests"
config.test_exec_root = config.clang_include_cleaner_binary_dir + "/unittests"

# Point the dynamic loader at dynamic libraries in 'lib'.
# FIXME: it seems every project has a copy of this logic. Move it somewhere.
import platform
if platform.system() == 'Darwin':
shlibpath_var = 'DYLD_LIBRARY_PATH'
elif platform.system() == 'Windows':
shlibpath_var = 'PATH'
else:
shlibpath_var = 'LD_LIBRARY_PATH'
config.environment[shlibpath_var] = os.path.pathsep.join((
"@SHLIBDIR@", "@LLVM_LIBS_DIR@",
config.environment.get(shlibpath_var,'')))
10 changes: 10 additions & 0 deletions clang-tools-extra/include-cleaner/test/Unit/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@LIT_SITE_CFG_IN_HEADER@
# This is a shim to run the gtest unittests in ../unittests using lit.

config.llvm_libs_dir = path("@LLVM_LIBS_DIR@")
config.shlibdir = path("@SHLIBDIR@")

config.clang_include_cleaner_binary_dir = path("@CMAKE_CURRENT_BINARY_DIR@/..")

# Delegate logic to lit.cfg.py.
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/Unit/lit.cfg.py")
16 changes: 16 additions & 0 deletions clang-tools-extra/include-cleaner/test/lit.cfg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import lit.llvm

lit.llvm.initialize(lit_config, config)
lit.llvm.llvm_config.use_default_substitutions()

config.name = 'ClangIncludeCleaner'
config.suffixes = ['.test', '.c', '.cpp']
config.excludes = ['Inputs']
config.test_format = lit.formats.ShTest(not lit.llvm.llvm_config.use_lit_shell)
config.test_source_root = config.clang_include_cleaner_source_dir + "/test"
config.test_exec_root = config.clang_include_cleaner_binary_dir + "/test"

config.environment['PATH'] = os.path.pathsep.join((
config.clang_tools_dir,
config.llvm_tools_dir,
config.environment['PATH']))
14 changes: 14 additions & 0 deletions clang-tools-extra/include-cleaner/test/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@LIT_SITE_CFG_IN_HEADER@

# Variables needed for common llvm config.
config.clang_tools_dir = path("@CURRENT_TOOLS_DIR@")
config.lit_tools_dir = path("@LLVM_LIT_TOOLS_DIR@")
config.llvm_tools_dir = path(lit_config.substitute("@LLVM_TOOLS_DIR@"))
config.llvm_libs_dir = path(lit_config.substitute("@LLVM_LIBS_DIR@"))
config.target_triple = "@TARGET_TRIPLE@"
config.python_executable = "@Python3_EXECUTABLE@"

config.clang_include_cleaner_source_dir = path("@CMAKE_CURRENT_SOURCE_DIR@/..")
config.clang_include_cleaner_binary_dir = path("@CMAKE_CURRENT_BINARY_DIR@/..")
# Delegate logic to lit.cfg.py.
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg.py")
27 changes: 27 additions & 0 deletions clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
set(LLVM_LINK_COMPONENTS
Support
TestingSupport
)

add_custom_target(ClangIncludeCleanerUnitTests)
add_unittest(ClangIncludeCleanerUnitTests ClangIncludeCleanerTests
WalkASTTest.cpp
)

target_include_directories(ClangIncludeCleanerTests
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../lib)

clang_target_link_libraries(ClangIncludeCleanerTests
PRIVATE
clangAST
clangBasic
clangFrontend
)

target_link_libraries(ClangIncludeCleanerTests
PRIVATE
clangIncludeCleaner
clangTesting
)

110 changes: 110 additions & 0 deletions clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "AnalysisInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Testing/TestAST.h"
#include "llvm/Support/Error.h"
#include "llvm/Testing/Support/Annotations.h"
#include "gtest/gtest.h"

namespace clang {
namespace include_cleaner {
namespace {

// Specifies a test of which symbols are referenced by a piece of code.
//
// Example:
// Target: int ^foo();
// Referencing: int x = ^foo();
// There must be exactly one referencing location marked.
void testWalk(llvm::StringRef TargetCode, llvm::StringRef ReferencingCode) {
llvm::Annotations Target(TargetCode);
llvm::Annotations Referencing(ReferencingCode);

TestInputs Inputs(Referencing.code());
Inputs.ExtraFiles["target.h"] = Target.code().str();
Inputs.ExtraArgs.push_back("-include");
Inputs.ExtraArgs.push_back("target.h");
TestAST AST(Inputs);
const auto &SM = AST.sourceManager();

// We're only going to record references from the nominated point,
// to the target file.
FileID ReferencingFile = SM.getMainFileID();
SourceLocation ReferencingLoc =
SM.getComposedLoc(ReferencingFile, Referencing.point());
FileID TargetFile = SM.translateFile(
llvm::cantFail(AST.fileManager().getFileRef("target.h")));

// Perform the walk, and capture the offsets of the referenced targets.
std::vector<size_t> ReferencedOffsets;
for (Decl *D : AST.context().getTranslationUnitDecl()->decls()) {
if (ReferencingFile != SM.getDecomposedExpansionLoc(D->getLocation()).first)
continue;
walkAST(*D, [&](SourceLocation Loc, NamedDecl &ND) {
if (SM.getFileLoc(Loc) != ReferencingLoc)
return;
auto NDLoc = SM.getDecomposedLoc(SM.getFileLoc(ND.getLocation()));
if (NDLoc.first != TargetFile)
return;
ReferencedOffsets.push_back(NDLoc.second);
});
}
llvm::sort(ReferencedOffsets);

// Compare results to the expected points.
// For each difference, show the target point in context, like a diagnostic.
std::string DiagBuf;
llvm::raw_string_ostream DiagOS(DiagBuf);
auto *DiagOpts = new DiagnosticOptions();
DiagOpts->ShowLevel = 0;
DiagOpts->ShowNoteIncludeStack = 0;
TextDiagnostic Diag(DiagOS, AST.context().getLangOpts(), DiagOpts);
auto DiagnosePoint = [&](const char *Message, unsigned Offset) {
Diag.emitDiagnostic(
FullSourceLoc(SM.getComposedLoc(TargetFile, Offset), SM),
DiagnosticsEngine::Note, Message, {}, {});
};
for (auto Expected : Target.points())
if (!llvm::is_contained(ReferencedOffsets, Expected))
DiagnosePoint("location not marked used", Expected);
for (auto Actual : ReferencedOffsets)
if (!llvm::is_contained(Target.points(), Actual))
DiagnosePoint("location unexpectedly used", Actual);

// If there were any differences, we print the entire referencing code once.
if (!DiagBuf.empty())
ADD_FAILURE() << DiagBuf << "\nfrom code:\n" << ReferencingCode;
}

TEST(WalkAST, DeclRef) {
testWalk("int ^x;", "int y = ^x;");
testWalk("int ^foo();", "int y = ^foo();");
testWalk("namespace ns { int ^x; }", "int y = ns::^x;");
testWalk("struct S { static int ^x; };", "int y = S::^x;");
// Canonical declaration only.
testWalk("extern int ^x; int x;", "int y = ^x;");
}

TEST(WalkAST, TagType) {
testWalk("struct ^S {};", "^S *y;");
testWalk("enum ^E {};", "^E *y;");
testWalk("struct ^S { static int x; };", "int y = ^S::x;");
}

TEST(WalkAST, Alias) {
testWalk(R"cpp(
namespace ns { int x; }
using ns::^x;
)cpp",
"int y = ^x;");
testWalk(R"cpp(
namespace ns { struct S; } // Not used
using ns::S; // FIXME: S should be used
)cpp",
"^S *x;");
}

} // namespace
} // namespace include_cleaner
} // namespace clang
17 changes: 7 additions & 10 deletions clang-tools-extra/pseudo/lib/Forest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,13 @@ std::string ForestNode::dumpRecursive(const Grammar &G,
} else if (P->kind() == Sequence) {
Children = P->elements();
if (Abbreviated) {
if (P->startTokenIndex() == End)
return;
for (size_t I = 0; I < Children.size(); ++I)
if (Children[I]->startTokenIndex() == P->startTokenIndex() &&
EndOfElement(I) == End) {
return Dump(
Children[I], End,
/*ElidedParent=*/ElidedParent.getValueOr(P->symbol()),
LineDec);
}
if (Children.size() == 1) {
assert(Children[0]->startTokenIndex() == P->startTokenIndex() &&
EndOfElement(0) == End);
return Dump(Children[0], End,
/*ElidedParent=*/ElidedParent.getValueOr(P->symbol()),
LineDec);
}
}
}

Expand Down
18 changes: 7 additions & 11 deletions clang-tools-extra/test/.gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,14 @@
# rely on or check fixed character -offset, Offset: or FileOffset: locations
# will fail when run on input files checked out with different line endings.

# Most test input files should use native line endings, to ensure that we run
# tests against both line ending types.
* text=auto

# These test input files rely on one-byte Unix (LF) line-endings, as they use
# fixed -offset, FileOffset:, or Offset: numbers in their tests.
clang-apply-replacements/ClangRenameClassReplacements.cpp text eol=lf
clang-apply-replacements/Inputs/basic/basic.h text eol=lf
clang-apply-replacements/Inputs/format/no.cpp text eol=lf
clang-apply-replacements/Inputs/format/yes.cpp text eol=lf
clang-tidy/infrastructure/export-diagnostics.cpp text eol=lf
clang-apply-replacements/ClangRenameClassReplacements.cpp -text
clang-apply-replacements/Inputs/basic/basic.h -text
clang-apply-replacements/Inputs/format/no.cpp -text
clang-apply-replacements/Inputs/format/yes.cpp -text
clang-tidy/infrastructure/export-diagnostics.cpp -text

# These test input files rely on two-byte Windows (CRLF) line endings.
clang-apply-replacements/Inputs/crlf/crlf.cpp text eol=crlf
clang-apply-replacements/Inputs/crlf/crlf.cpp.expected text eol=crlf
clang-apply-replacements/Inputs/crlf/crlf.cpp -text
clang-apply-replacements/Inputs/crlf/crlf.cpp.expected -text
Original file line number Diff line number Diff line change
Expand Up @@ -281,27 +281,14 @@ inline void used_ifndef() {}
#define EPS2 1e5
#define EPS3 1.

#define DO_RED draw(RED)
#define DO_GREEN draw(GREEN)
#define DO_BLUE draw(BLUE)

#define FN_RED(x) draw(RED | x)
#define FN_GREEN(x) draw(GREEN | x)
#define FN_BLUE(x) draw(BLUE | x)

extern void draw(unsigned int Color);

void f()
{
// Usage of macros converted to enums should still compile.
draw(RED);
draw(GREEN);
draw(BLUE);
DO_RED;
DO_GREEN;
DO_BLUE;
FN_RED(0);
FN_GREEN(0);
FN_BLUE(0);
draw(GREEN | RED);
draw(BLUE + RED);
}

// Ignore macros defined inside a top-level function definition.
Expand Down Expand Up @@ -389,3 +376,17 @@ using Data2 =
constexpr int
#define INSIDE17 17
value = INSIDE17;

// Ignore macros used in the expansion of other macros
#define INSIDE18 18
#define INSIDE19 19

#define CONCAT(n_, s_) n_##s_
#define FN_NAME(n_, s_) CONCAT(n_, s_)

extern void FN_NAME(g, INSIDE18)();

void gg()
{
g18();
}
4 changes: 3 additions & 1 deletion clang/cmake/caches/3-stage-base.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "")

set(LLVM_ENABLE_PROJECTS "clang;lld" CACHE STRING "")
set(LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi" CACHE STRING "")

if(APPLE)
# Use LLD to have fewer requirements on system linker, unless we're on an apple
Expand Down
3 changes: 2 additions & 1 deletion clang/cmake/caches/PGO-stage2.cmake
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "")
set(LLVM_ENABLE_PROJECTS "clang;lld" CACHE STRING "")
set(LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi" CACHE STRING "")
6 changes: 4 additions & 2 deletions clang/cmake/caches/PGO.cmake
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "")

set(LLVM_TARGETS_TO_BUILD X86 CACHE STRING "")
set(LLVM_ENABLE_PROJECTS "clang;lld" CACHE STRING "")
set(LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi" CACHE STRING "")

set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "")
set(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED ON CACHE BOOL "")
set(CLANG_BOOTSTRAP_TARGETS
generate-profdata
Expand Down
3 changes: 2 additions & 1 deletion clang/docs/AddressSanitizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ following types of bugs:
* Out-of-bounds accesses to heap, stack and globals
* Use-after-free
* Use-after-return (clang flag ``-fsanitize-address-use-after-return=(never|runtime|always)`` default: ``runtime``)
* Disable ``runtime`` with: ``ASAN_OPTIONS=detect_stack_use_after_return=0``
* Enable with: ``ASAN_OPTIONS=detect_stack_use_after_return=1`` (already enabled on Linux).
* Disable with: ``ASAN_OPTIONS=detect_stack_use_after_return=0``.
* Use-after-scope (clang flag ``-fsanitize-address-use-after-scope``)
* Double-free, invalid free
* Memory leaks (experimental)
Expand Down
22 changes: 18 additions & 4 deletions clang/docs/ClangCommandLineReference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,22 @@ Flush denormal floating point values to zero in CUDA/HIP device mode.

Specify comma-separated list of triples OpenMP offloading targets to be supported

.. option:: -fopenmp-new-driver, -fno-openmp-new-driver

Use the new driver for OpenMP offloading.

.. option:: --offload-new-driver, --no-offload-new-driver

Use the new driver for offloading compilation.

.. option:: --offload-host-only

Only compile for the host when offloading.

.. option:: --offload-device-only

Only compile for the device when offloading.

.. option:: -force\_cpusubtype\_ALL

.. program:: clang1
Expand Down Expand Up @@ -801,10 +817,6 @@ Generate Interface Stub Files, emit merged text not binary.

Extract API information

.. option:: -fopenmp-new-driver, fno-openmp-new-driver

Use the new driver for OpenMP offloading.

.. option:: -fsyntax-only

.. option:: -module-file-info
Expand Down Expand Up @@ -3563,6 +3575,8 @@ PowerPC

.. option:: -mcrbits, -mno-crbits

Control the CR-bit tracking feature on PowerPC. ``-mcrbits`` (the enablement of CR-bit tracking support) is the default for POWER8 and above, as well as for all other CPUs when optimization is applied (-O2 and above).

.. option:: -mcrypto, -mno-crypto

.. option:: -mdirect-move, -mno-direct-move
Expand Down
5 changes: 5 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,11 @@ The following type trait primitives are supported by Clang. Those traits marked
* ``__is_trivially_constructible`` (C++, GNU, Microsoft)
* ``__is_trivially_copyable`` (C++, GNU, Microsoft)
* ``__is_trivially_destructible`` (C++, MSVC 2013)
* ``__is_trivially_relocatable`` (Clang): Returns true if moving an object
of the given type, and then destroying the source object, is known to be
functionally equivalent to copying the underlying bytes and then dropping the
source object on the floor. This is true of trivial types and types which
were made trivially relocatable via the ``clang::trivial_abi`` attribute.
* ``__is_union`` (C++, GNU, Microsoft, Embarcadero)
* ``__is_unsigned`` (C++, Embarcadero):
Returns false for enumeration types. Note, before Clang 13, returned true for
Expand Down
25 changes: 16 additions & 9 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,17 @@ Improvements to Clang's diagnostics
now only diagnose deprecated declarations and definitions of functions
without a prototype where the behavior in C2x will remain correct. This
diagnostic remains off by default but is now enabled via ``-pedantic`` due to
it being a deprecation warning. ``-Wdeprecated-non-prototype`` will diagnose
cases where the deprecated declarations or definitions of a function without
a prototype will change behavior in C2x. Additionally, it will diagnose calls
which pass arguments to a function without a prototype. This warning is
enabled only when the ``-Wdeprecated-non-prototype`` option is enabled at the
function declaration site, which allows a developer to disable the diagnostic
for all callers at the point of declaration. This diagnostic is grouped under
the ``-Wstrict-prototypes`` warning group, but is enabled by default.
it being a deprecation warning. ``-Wstrict-prototypes`` has no effect in C2x
or when ``-fno-knr-functions`` is enabled. ``-Wdeprecated-non-prototype``
will diagnose cases where the deprecated declarations or definitions of a
function without a prototype will change behavior in C2x. Additionally, it
will diagnose calls which pass arguments to a function without a prototype.
This warning is enabled only when the ``-Wdeprecated-non-prototype`` option
is enabled at the function declaration site, which allows a developer to
disable the diagnostic for all callers at the point of declaration. This
diagnostic is grouped under the ``-Wstrict-prototypes`` warning group, but is
enabled by default. ``-Wdeprecated-non-prototype`` has no effect in C2x or
when ``-fno-knr-functions`` is enabled.
- Clang now appropriately issues an error in C when a definition of a function
without a prototype and with no arguments is an invalid redeclaration of a
function with a prototype. e.g., ``void f(int); void f() {}`` is now properly
Expand All @@ -179,7 +182,7 @@ Non-comprehensive list of changes in this release
- Remove anonymous tag locations.
- Beautify dump format, add indent for nested struct and struct members.
- Previously disabled sanitizer options now enabled by default:
- ASAN_OPTIONS=detect_stack_use_after_return=1 (except Windows).
- ASAN_OPTIONS=detect_stack_use_after_return=1 (only on Linux).
- MSAN_OPTIONS=poison_in_dtor=1.

New Compiler Flags
Expand Down Expand Up @@ -262,6 +265,10 @@ C++ Language Changes in Clang
``std::move_if_noexcept``, ``std::addressof``, and ``std::as_const``. These
are now treated as compiler builtins and implemented directly, rather than
instantiating the definition from the standard library.
- Fixed mangling of nested dependent names such as ``T::a::b``, where ``T`` is a
template parameter, to conform to the Itanium C++ ABI and be compatible with
GCC. This breaks binary compatibility with code compiled with earlier versions
of clang; use the ``-fclang-abi-compat=14`` option to get the old mangling.

C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^
Expand Down
15 changes: 7 additions & 8 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1219,23 +1219,22 @@ for generating PCH files:
Using a PCH File
^^^^^^^^^^^^^^^^

A PCH file can then be used as a prefix header when a :option:`-include`
A PCH file can then be used as a prefix header when a ``-include-pch``
option is passed to ``clang``:

.. code-block:: console
$ clang -include test.h test.c -o test
$ clang -include-pch test.h.pch test.c -o test
The ``clang`` driver will first check if a PCH file for ``test.h`` is
The ``clang`` driver will check if the PCH file ``test.h.pch`` is
available; if so, the contents of ``test.h`` (and the files it includes)
will be processed from the PCH file. Otherwise, Clang falls back to
directly processing the content of ``test.h``. This mirrors the behavior
of GCC.
will be processed from the PCH file. Otherwise, Clang will report an error.

.. note::

Clang does *not* automatically use PCH files for headers that are directly
included within a source file. For example:
included within a source file or indirectly via :option:`-include`.
For example:

.. code-block:: console
Expand All @@ -1246,7 +1245,7 @@ of GCC.
In this example, ``clang`` will not automatically use the PCH file for
``test.h`` since ``test.h`` was included directly in the source file and not
specified on the command line using :option:`-include`.
specified on the command line using ``-include-pch``.

Relocatable PCH Files
^^^^^^^^^^^^^^^^^^^^^
Expand Down
19 changes: 19 additions & 0 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2268,6 +2268,25 @@ Finds calls to the ``putenv`` function which pass a pointer to an automatic vari
return putenv(env); // putenv function should not be called with auto variables
}
Limitations:
- Technically, one can pass automatic variables to ``putenv``,
but one needs to ensure that the given environment key stays
alive until it's removed or overwritten.
Since the analyzer cannot keep track of which envvars get overwritten
and when, it needs to be slightly more aggressive and warn for such
cases too, leading in some cases to false-positive reports like this:
.. code-block:: c
void baz() {
char env[] = "NAME=value";
putenv(env); // false-positive warning: putenv function should not be called...
// More code...
putenv((char *)"NAME=anothervalue");
// This putenv call overwrites the previous entry, thus that can no longer dangle.
} // 'env' array becomes dead only here.
alpha.security.cert.env
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
~CUDAConstantEvalContextRAII() { Ctx.CUDAConstantEvalCtx = SavedCtx; }
};

/// Current CUDA name mangling is for device name in host compilation.
bool CUDAMangleDeviceNameInHostCompilation = false;

/// Returns the dynamic AST node parent map context.
ParentMapContext &getParentMapContext();

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4072,7 +4072,7 @@ class RecordDecl : public TagDecl {

void setIsRandomized(bool V) { RecordDeclBits.IsRandomized = V; }

void reorderFields(const SmallVectorImpl<Decl *> &Fields);
void reorderDecls(const SmallVectorImpl<Decl *> &Decls);

/// Determines whether this declaration represents the
/// injected class name.
Expand Down
12 changes: 8 additions & 4 deletions clang/include/clang/AST/DeclObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -1951,7 +1951,10 @@ class ObjCIvarDecl : public FieldDecl {
/// in; this is either the interface where the ivar was declared, or the
/// interface the ivar is conceptually a part of in the case of synthesized
/// ivars.
const ObjCInterfaceDecl *getContainingInterface() const;
ObjCInterfaceDecl *getContainingInterface();
const ObjCInterfaceDecl *getContainingInterface() const {
return const_cast<ObjCIvarDecl *>(this)->getContainingInterface();
}

ObjCIvarDecl *getNextIvar() { return NextIvar; }
const ObjCIvarDecl *getNextIvar() const { return NextIvar; }
Expand Down Expand Up @@ -2885,15 +2888,16 @@ ObjCInterfaceDecl::filtered_category_iterator<Filter>::operator++() {
}

inline bool ObjCInterfaceDecl::isVisibleCategory(ObjCCategoryDecl *Cat) {
return Cat->isUnconditionallyVisible();
return !Cat->isInvalidDecl() && Cat->isUnconditionallyVisible();
}

inline bool ObjCInterfaceDecl::isVisibleExtension(ObjCCategoryDecl *Cat) {
return Cat->IsClassExtension() && Cat->isUnconditionallyVisible();
return !Cat->isInvalidDecl() && Cat->IsClassExtension() &&
Cat->isUnconditionallyVisible();
}

inline bool ObjCInterfaceDecl::isKnownExtension(ObjCCategoryDecl *Cat) {
return Cat->IsClassExtension();
return !Cat->isInvalidDecl() && Cat->IsClassExtension();
}

} // namespace clang
Expand Down
5 changes: 1 addition & 4 deletions clang/include/clang/AST/Randstruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
#define LLVM_CLANG_AST_RANDSTRUCT_H

namespace llvm {
template <typename T> class ArrayRef;
template <typename T> class SmallVectorImpl;
class StringRef;
} // end namespace llvm

namespace clang {
Expand All @@ -28,8 +26,7 @@ class RecordDecl;

namespace randstruct {

bool randomizeStructureLayout(const ASTContext &Context, llvm::StringRef Name,
llvm::ArrayRef<Decl *> Fields,
bool randomizeStructureLayout(const ASTContext &Context, RecordDecl *RD,
llvm::SmallVectorImpl<Decl *> &FinalOrdering);

} // namespace randstruct
Expand Down
151 changes: 101 additions & 50 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,19 @@
#ifndef LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
#define LLVM_CLANG_AST_RECURSIVEASTVISITOR_H

#include "clang/AST/ASTConcept.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/LambdaCapture.h"
Expand Down Expand Up @@ -319,11 +320,6 @@ template <typename Derived> class RecursiveASTVisitor {
bool TraverseSynOrSemInitListExpr(InitListExpr *S,
DataRecursionQueue *Queue = nullptr);

/// Recursively visit a reference to a concept with potential arguments.
///
/// \returns false if the visitation was terminated early, true otherwise.
bool TraverseConceptReference(const ConceptReference &C);

/// Recursively visit an Objective-C protocol reference with location
/// information.
///
Expand Down Expand Up @@ -475,11 +471,21 @@ template <typename Derived> class RecursiveASTVisitor {
DEF_TRAVERSE_TMPL_INST(Function)
#undef DEF_TRAVERSE_TMPL_INST

bool TraverseTypeConstraint(const TypeConstraint *C);

bool TraverseConceptRequirement(concepts::Requirement *R);
bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R);
bool TraverseConceptExprRequirement(concepts::ExprRequirement *R);
bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R);

bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue);

private:
// These are helper methods used by more than one Traverse* method.
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
/// Traverses the qualifier, name and template arguments of a concept
/// reference.
bool TraverseConceptReferenceHelper(const ConceptReference &C);

// Traverses template parameter lists of either a DeclaratorDecl or TagDecl.
template <typename T>
Expand Down Expand Up @@ -511,6 +517,55 @@ template <typename Derived> class RecursiveASTVisitor {
bool PostVisitStmt(Stmt *S);
};

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTypeConstraint(
const TypeConstraint *C) {
if (!getDerived().shouldVisitImplicitCode()) {
TRY_TO(TraverseConceptReferenceHelper(*C));
return true;
}
if (Expr *IDC = C->getImmediatelyDeclaredConstraint()) {
TRY_TO(TraverseStmt(IDC));
} else {
// Avoid traversing the ConceptReference in the TypeConstraint
// if we have an immediately-declared-constraint, otherwise
// we'll end up visiting the concept and the arguments in
// the TC twice.
TRY_TO(TraverseConceptReferenceHelper(*C));
}
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseConceptRequirement(
concepts::Requirement *R) {
switch (R->getKind()) {
case concepts::Requirement::RK_Type:
return getDerived().TraverseConceptTypeRequirement(
cast<concepts::TypeRequirement>(R));
case concepts::Requirement::RK_Simple:
case concepts::Requirement::RK_Compound:
return getDerived().TraverseConceptExprRequirement(
cast<concepts::ExprRequirement>(R));
case concepts::Requirement::RK_Nested:
return getDerived().TraverseConceptNestedRequirement(
cast<concepts::NestedRequirement>(R));
}
llvm_unreachable("unexpected case");
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseConceptReferenceHelper(
const ConceptReference &C) {
TRY_TO(TraverseNestedNameSpecifierLoc(C.getNestedNameSpecifierLoc()));
TRY_TO(TraverseDeclarationNameInfo(C.getConceptNameInfo()));
if (C.hasExplicitTemplateArgs())
TRY_TO(TraverseTemplateArgumentLocsHelper(
C.getTemplateArgsAsWritten()->getTemplateArgs(),
C.getTemplateArgsAsWritten()->NumTemplateArgs));
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
DataRecursionQueue *Queue) {
Expand All @@ -530,6 +585,40 @@ bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,

#undef DISPATCH_STMT

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseConceptTypeRequirement(
concepts::TypeRequirement *R) {
if (R->isSubstitutionFailure())
return true;
return getDerived().TraverseTypeLoc(R->getType()->getTypeLoc());
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseConceptExprRequirement(
concepts::ExprRequirement *R) {
if (!R->isExprSubstitutionFailure())
TRY_TO(TraverseStmt(R->getExpr()));
auto &RetReq = R->getReturnTypeRequirement();
if (RetReq.isTypeConstraint()) {
if (getDerived().shouldVisitImplicitCode()) {
TRY_TO(TraverseTemplateParameterListHelper(
RetReq.getTypeConstraintTemplateParameterList()));
} else {
// Template parameter list is implicit, visit constraint directly.
TRY_TO(TraverseTypeConstraint(RetReq.getTypeConstraint()));
}
}
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseConceptNestedRequirement(
concepts::NestedRequirement *R) {
if (!R->isSubstitutionFailure())
return getDerived().TraverseStmt(R->getConstraintExpr());
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::PostVisitStmt(Stmt *S) {
// In pre-order traversal mode, each Traverse##STMT method is responsible for
Expand Down Expand Up @@ -1007,7 +1096,6 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, {
DEF_TRAVERSE_TYPE(AutoType, {
TRY_TO(TraverseType(T->getDeducedType()));
if (T->isConstrained()) {
TRY_TO(TraverseDecl(T->getTypeConstraintConcept()));
TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
}
})
Expand Down Expand Up @@ -1838,17 +1926,8 @@ DEF_TRAVERSE_DECL(BuiltinTemplateDecl, {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateTypeParamDeclConstraints(
const TemplateTypeParmDecl *D) {
if (const auto *TC = D->getTypeConstraint()) {
if (Expr *IDC = TC->getImmediatelyDeclaredConstraint()) {
TRY_TO(TraverseStmt(IDC));
} else {
// Avoid traversing the ConceptReference in the TypeCosntraint
// if we have an immediately-declared-constraint, otherwise
// we'll end up visiting the concept and the arguments in
// the TC twice.
TRY_TO(TraverseConceptReference(*TC));
}
}
if (const auto *TC = D->getTypeConstraint())
TRY_TO(TraverseTypeConstraint(TC));
return true;
}

Expand Down Expand Up @@ -2435,18 +2514,6 @@ bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
return true;
}

template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseConceptReference(
const ConceptReference &C) {
TRY_TO(TraverseNestedNameSpecifierLoc(C.getNestedNameSpecifierLoc()));
TRY_TO(TraverseDeclarationNameInfo(C.getConceptNameInfo()));
if (C.hasExplicitTemplateArgs())
TRY_TO(TraverseTemplateArgumentLocsHelper(
C.getTemplateArgsAsWritten()->getTemplateArgs(),
C.getTemplateArgsAsWritten()->NumTemplateArgs));
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseObjCProtocolLoc(
ObjCProtocolLoc ProtocolLoc) {
Expand Down Expand Up @@ -2825,31 +2892,15 @@ DEF_TRAVERSE_STMT(CoyieldExpr, {
}
})

DEF_TRAVERSE_STMT(ConceptSpecializationExpr, {
TRY_TO(TraverseConceptReference(*S));
})
DEF_TRAVERSE_STMT(ConceptSpecializationExpr,
{ TRY_TO(TraverseConceptReferenceHelper(*S)); })

DEF_TRAVERSE_STMT(RequiresExpr, {
TRY_TO(TraverseDecl(S->getBody()));
for (ParmVarDecl *Parm : S->getLocalParameters())
TRY_TO(TraverseDecl(Parm));
for (concepts::Requirement *Req : S->getRequirements())
if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) {
if (!TypeReq->isSubstitutionFailure())
TRY_TO(TraverseTypeLoc(TypeReq->getType()->getTypeLoc()));
} else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) {
if (!ExprReq->isExprSubstitutionFailure())
TRY_TO(TraverseStmt(ExprReq->getExpr()));
auto &RetReq = ExprReq->getReturnTypeRequirement();
if (RetReq.isTypeConstraint()) {
TRY_TO(TraverseStmt(
RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint()));
}
} else {
auto *NestedReq = cast<concepts::NestedRequirement>(Req);
if (!NestedReq->isSubstitutionFailure())
TRY_TO(TraverseStmt(NestedReq->getConstraintExpr()));
}
TRY_TO(TraverseConceptRequirement(Req));
})

// These literals (all of them) do not need any action.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,8 @@ class QualType {
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
bool isTriviallyCopyableType(const ASTContext &Context) const;

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

/// Returns true if it is a class and it might be dynamic.
bool mayBeDynamicClass() const;
Expand Down
9 changes: 3 additions & 6 deletions clang/include/clang/Analysis/Analyses/ThreadSafety.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,8 @@ class ThreadSafetyHandler {
virtual ~ThreadSafetyHandler();

/// Warn about lock expressions which fail to resolve to lockable objects.
/// \param Kind -- the capability's name parameter (role, mutex, etc).
/// \param Loc -- the SourceLocation of the unresolved expression.
virtual void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) {}
virtual void handleInvalidLockExp(SourceLocation Loc) {}

/// Warn about unlock function calls that do not have a prior matching lock
/// expression.
Expand Down Expand Up @@ -169,14 +168,12 @@ class ThreadSafetyHandler {
SourceLocation Loc2) {}

/// Warn when a protected operation occurs while no locks are held.
/// \param Kind -- the capability's name parameter (role, mutex, etc).
/// \param D -- The decl for the protected variable or function
/// \param POK -- The kind of protected operation (e.g. variable access)
/// \param AK -- The kind of access (i.e. read or write) that occurred
/// \param Loc -- The location of the protected operation.
virtual void handleNoMutexHeld(StringRef Kind, const NamedDecl *D,
ProtectedOperationKind POK, AccessKind AK,
SourceLocation Loc) {}
virtual void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
AccessKind AK, SourceLocation Loc) {}

/// Warn when a protected operation occurs while the specific mutex protecting
/// the operation is not locked.
Expand Down
47 changes: 28 additions & 19 deletions clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "clang/Analysis/CFG.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include <sstream>
Expand Down Expand Up @@ -269,56 +270,64 @@ class CFGWalker {
// translateAttrExpr needs it, but that should be moved too.
class CapabilityExpr {
private:
/// The capability expression.
const til::SExpr* CapExpr;
/// The capability expression and whether it's negated.
llvm::PointerIntPair<const til::SExpr *, 1, bool> CapExpr;

/// True if this is a negative capability.
bool Negated;
/// The kind of capability as specified by @ref CapabilityAttr::getName.
StringRef CapKind;

public:
CapabilityExpr(const til::SExpr *E, bool Neg) : CapExpr(E), Negated(Neg) {}
CapabilityExpr() : CapExpr(nullptr, false) {}
CapabilityExpr(const til::SExpr *E, StringRef Kind, bool Neg)
: CapExpr(E, Neg), CapKind(Kind) {}

const til::SExpr* sexpr() const { return CapExpr; }
bool negative() const { return Negated; }
// Don't allow implicitly-constructed StringRefs since we'll capture them.
template <typename T> CapabilityExpr(const til::SExpr *, T, bool) = delete;

const til::SExpr *sexpr() const { return CapExpr.getPointer(); }
StringRef getKind() const { return CapKind; }
bool negative() const { return CapExpr.getInt(); }

CapabilityExpr operator!() const {
return CapabilityExpr(CapExpr, !Negated);
return CapabilityExpr(CapExpr.getPointer(), CapKind, !CapExpr.getInt());
}

bool equals(const CapabilityExpr &other) const {
return (Negated == other.Negated) && sx::equals(CapExpr, other.CapExpr);
return (negative() == other.negative()) &&
sx::equals(sexpr(), other.sexpr());
}

bool matches(const CapabilityExpr &other) const {
return (Negated == other.Negated) && sx::matches(CapExpr, other.CapExpr);
return (negative() == other.negative()) &&
sx::matches(sexpr(), other.sexpr());
}

bool matchesUniv(const CapabilityExpr &CapE) const {
return isUniversal() || matches(CapE);
}

bool partiallyMatches(const CapabilityExpr &other) const {
return (Negated == other.Negated) &&
sx::partiallyMatches(CapExpr, other.CapExpr);
return (negative() == other.negative()) &&
sx::partiallyMatches(sexpr(), other.sexpr());
}

const ValueDecl* valueDecl() const {
if (Negated || CapExpr == nullptr)
if (negative() || sexpr() == nullptr)
return nullptr;
if (const auto *P = dyn_cast<til::Project>(CapExpr))
if (const auto *P = dyn_cast<til::Project>(sexpr()))
return P->clangDecl();
if (const auto *P = dyn_cast<til::LiteralPtr>(CapExpr))
if (const auto *P = dyn_cast<til::LiteralPtr>(sexpr()))
return P->clangDecl();
return nullptr;
}

std::string toString() const {
if (Negated)
return "!" + sx::toString(CapExpr);
return sx::toString(CapExpr);
if (negative())
return "!" + sx::toString(sexpr());
return sx::toString(sexpr());
}

bool shouldIgnore() const { return CapExpr == nullptr; }
bool shouldIgnore() const { return sexpr() == nullptr; }

bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include <cassert>
#include <memory>
#include <type_traits>
Expand All @@ -45,9 +46,6 @@ class DataflowAnalysisContext {
assert(this->S != nullptr);
}

/// Returns the SAT solver instance that is available in this context.
Solver &getSolver() const { return *S; }

/// Takes ownership of `Loc` and returns a reference to it.
///
/// Requirements:
Expand Down Expand Up @@ -151,7 +149,39 @@ class DataflowAnalysisContext {
/// calls with the same argument will return the same result.
BoolValue &getOrCreateNegationValue(BoolValue &Val);

/// Creates a fresh flow condition and returns a token that identifies it. The
/// token can be used to perform various operations on the flow condition such
/// as adding constraints to it, forking it, joining it with another flow
/// condition, or checking implications.
AtomicBoolValue &makeFlowConditionToken();

/// Adds `Constraint` to the flow condition identified by `Token`.
void addFlowConditionConstraint(AtomicBoolValue &Token,
BoolValue &Constraint);

/// Creates a new flow condition with the same constraints as the flow
/// condition identified by `Token` and returns its token.
AtomicBoolValue &forkFlowCondition(AtomicBoolValue &Token);

/// Creates a new flow condition that represents the disjunction of the flow
/// conditions identified by `FirstToken` and `SecondToken`, and returns its
/// token.
AtomicBoolValue &joinFlowConditions(AtomicBoolValue &FirstToken,
AtomicBoolValue &SecondToken);

/// Returns true if and only if the constraints of the flow condition
/// identified by `Token` imply that `Val` is true.
bool flowConditionImplies(AtomicBoolValue &Token, BoolValue &Val);

private:
/// Adds all constraints of the flow condition identified by `Token` and all
/// of its transitive dependencies to `Constraints`. `VisitedTokens` is used
/// to track tokens of flow conditions that were already visited by recursive
/// calls.
void addTransitiveFlowConditionConstraints(
AtomicBoolValue &Token, llvm::DenseSet<BoolValue *> &Constraints,
llvm::DenseSet<AtomicBoolValue *> &VisitedTokens) const;

std::unique_ptr<Solver> S;

// Storage for the state of a program.
Expand All @@ -178,6 +208,27 @@ class DataflowAnalysisContext {
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, DisjunctionValue *>
DisjunctionVals;
llvm::DenseMap<BoolValue *, NegationValue *> NegationVals;

// Flow conditions are tracked symbolically: each unique flow condition is
// associated with a fresh symbolic variable (token), bound to the clause that
// defines the flow condition. Conceptually, each binding corresponds to an
// "iff" of the form `FC <=> (C1 ^ C2 ^ ...)` where `FC` is a flow condition
// token (an atomic boolean) and `Ci`s are the set of constraints in the flow
// flow condition clause. Internally, we do not record the formula directly as
// an "iff". Instead, a flow condition clause is encoded as conjuncts of the
// form `(FC v !C1 v !C2 v ...) ^ (C1 v !FC) ^ (C2 v !FC) ^ ...`. The first
// conjuct is stored in the `FlowConditionFirstConjuncts` map and the set of
// remaining conjuncts are stored in the `FlowConditionRemainingConjuncts`
// map, both keyed by the token of the flow condition.
//
// Flow conditions depend on other flow conditions if they are created using
// `forkFlowCondition` or `joinFlowConditions`. The graph of flow condition
// dependencies is stored in the `FlowConditionDeps` map.
llvm::DenseMap<AtomicBoolValue *, llvm::DenseSet<AtomicBoolValue *>>
FlowConditionDeps;
llvm::DenseMap<AtomicBoolValue *, BoolValue *> FlowConditionFirstConjuncts;
llvm::DenseMap<AtomicBoolValue *, llvm::DenseSet<BoolValue *>>
FlowConditionRemainingConjuncts;
};

} // namespace dataflow
Expand Down
15 changes: 10 additions & 5 deletions clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,13 @@ class Environment {

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program.
explicit Environment(DataflowAnalysisContext &DACtx) : DACtx(&DACtx) {}
explicit Environment(DataflowAnalysisContext &DACtx);

Environment(const Environment &Other);
Environment &operator=(const Environment &Other);

Environment(Environment &&Other) = default;
Environment &operator=(Environment &&Other) = default;

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program.
Expand Down Expand Up @@ -297,9 +303,8 @@ class Environment {
: makeAnd(makeImplication(LHS, RHS), makeImplication(RHS, LHS));
}

const llvm::DenseSet<BoolValue *> &getFlowConditionConstraints() const {
return FlowConditionConstraints;
}
/// Returns the token that identifies the flow condition of the environment.
AtomicBoolValue &getFlowConditionToken() const { return *FlowConditionToken; }

/// Adds `Val` to the set of clauses that constitute the flow condition.
void addToFlowCondition(BoolValue &Val);
Expand Down Expand Up @@ -345,7 +350,7 @@ class Environment {
std::pair<StructValue *, const ValueDecl *>>
MemberLocToStruct;

llvm::DenseSet<BoolValue *> FlowConditionConstraints;
AtomicBoolValue *FlowConditionToken;
};

} // namespace dataflow
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3333,6 +3333,9 @@ If a type is trivial for the purposes of calls, has a non-trivial destructor,
and is passed as an argument by value, the convention is that the callee will
destroy the object before returning.

If a type is trivial for the purpose of calls, it is assumed to be trivially
relocatable for the purpose of ``__is_trivially_relocatable``.

Attribute ``trivial_abi`` has no effect in the following cases:

- The class directly declares a virtual base or virtual methods.
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ BUILTIN(__builtin_reduce_min, "v.", "nct")
BUILTIN(__builtin_reduce_xor, "v.", "nct")
BUILTIN(__builtin_reduce_or, "v.", "nct")
BUILTIN(__builtin_reduce_and, "v.", "nct")
BUILTIN(__builtin_reduce_add, "v.", "nct")

BUILTIN(__builtin_matrix_transpose, "v.", "nFt")
BUILTIN(__builtin_matrix_column_major_load, "v.", "nFt")
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/BuiltinsRISCV.def
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ TARGET_BUILTIN(__builtin_riscv_orc_b_32, "ZiZi", "nc", "zbb")
TARGET_BUILTIN(__builtin_riscv_orc_b_64, "WiWi", "nc", "zbb,64bit")
TARGET_BUILTIN(__builtin_riscv_clz_32, "ZiZi", "nc", "zbb")
TARGET_BUILTIN(__builtin_riscv_clz_64, "WiWi", "nc", "zbb,64bit")
TARGET_BUILTIN(__builtin_riscv_ctz_32, "ZiZi", "nc", "zbb")
TARGET_BUILTIN(__builtin_riscv_ctz_64, "WiWi", "nc", "zbb,64bit")

// Zbc or Zbkc extension
TARGET_BUILTIN(__builtin_riscv_clmul, "LiLiLi", "nc", "zbc|zbkc")
Expand Down
2 changes: 0 additions & 2 deletions clang/include/clang/Basic/BuiltinsX86.def
Original file line number Diff line number Diff line change
Expand Up @@ -1990,8 +1990,6 @@ TARGET_BUILTIN(__builtin_ia32_selectss_128, "V4fUcV4fV4f", "ncV:128:", "avx512f"
TARGET_BUILTIN(__builtin_ia32_selectsd_128, "V2dUcV2dV2d", "ncV:128:", "avx512f")

// generic reduction intrinsics
TARGET_BUILTIN(__builtin_ia32_reduce_add_d512, "iV16i", "ncV:512:", "avx512f")
TARGET_BUILTIN(__builtin_ia32_reduce_add_q512, "OiV8Oi", "ncV:512:", "avx512f")
TARGET_BUILTIN(__builtin_ia32_reduce_fadd_pd512, "ddV8d", "ncV:512:", "avx512f")
TARGET_BUILTIN(__builtin_ia32_reduce_fadd_ps512, "ffV16f", "ncV:512:", "avx512f")
TARGET_BUILTIN(__builtin_ia32_reduce_fadd_ph512, "xxV32x", "ncV:512:", "avx512fp16")
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,16 @@ enum class CudaArch {
GFX1034,
GFX1035,
GFX1036,
GFX1100,
GFX1101,
GFX1102,
GFX1103,
Generic, // A processor model named 'generic' if the target backend defines a
// public one.
LAST,

CudaDefault = CudaArch::SM_35,
HIPDefault = CudaArch::GFX803,
};

static inline bool IsNVIDIAGpuArch(CudaArch A) {
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def err_drv_no_cuda_libdevice : Error<
"cannot find libdevice for %0; provide path to different CUDA installation "
"via '--cuda-path', or pass '-nocudalib' to build without linking with "
"libdevice">;
def err_drv_no_rdc_new_driver : Error<
"Using '--offload-new-driver' requires '-fgpu-rdc'">;

def err_drv_no_rocm_device_lib : Error<
"cannot find ROCm device library%select{| for %1|for ABI version %1}0; provide its path via "
Expand Down Expand Up @@ -665,4 +667,13 @@ def err_drv_target_variant_invalid : Error<
def err_drv_invalid_directx_shader_module : Error<
"invalid profile : %0">;

def err_drv_invalid_range_dxil_validator_version : Error<
"invalid validator version : %0\n"
"Validator version must be less than or equal to current internal version.">;
def err_drv_invalid_format_dxil_validator_version : Error<
"invalid validator version : %0\n"
"Format of validator version is \"<major>.<minor>\" (ex:\"1.4\").">;
def err_drv_invalid_empty_dxil_validator_version : Error<
"invalid validator version : %0\n"
"If validator major version is 0, minor version must also be 0.">;
}
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1362,3 +1362,6 @@ def PedanticMacros : DiagGroup<"pedantic-macros",

def BranchProtection : DiagGroup<"branch-protection">;

// HLSL diagnostic groups
// Warnings for HLSL Clang extensions
def HLSLExtension : DiagGroup<"hlsl-extensions">;
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/DiagnosticIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
/// "deprecated-declarations".
static StringRef getWarningOptionForGroup(diag::Group);

/// Given a group ID, returns the flag that toggles the group.
/// For example, for "deprecated-declarations", returns
/// Group::DeprecatedDeclarations.
static llvm::Optional<diag::Group> getGroupForWarningOption(StringRef);

/// Return the lowest-level group that contains the specified diagnostic.
static llvm::Optional<diag::Group> getGroupForDiag(unsigned DiagID);

/// Return the lowest-level warning option that enables the specified
/// diagnostic.
///
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1599,5 +1599,8 @@ def note_max_tokens_total_override : Note<"total token limit set here">;
def err_expected_semantic_identifier : Error<
"expected HLSL Semantic identifier">;
def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">;
def ext_hlsl_access_specifiers : ExtWarn<
"access specifiers are a clang HLSL extension">,
InGroup<HLSLExtension>;

} // end of Parser diagnostics
2 changes: 0 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10198,8 +10198,6 @@ def err_opencl_scalar_type_rank_greater_than_vector_type : Error<
"element. (%0 and %1)">;
def err_bad_kernel_param_type : Error<
"%0 cannot be used as the type of a kernel parameter">;
def err_opencl_implicit_function_decl : Error<
"implicit declaration of function %0 is invalid in OpenCL">;
def err_record_with_pointers_kernel_param : Error<
"%select{struct|union}0 kernel parameters may not contain pointers">;
def note_within_field_of_type : Note<
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ class LangOptions : public LangOptionsBase {
/// This causes clang to not pack non-POD members of packed structs.
Ver13,

/// Attempt to be ABI-compatible with code generated by Clang 14.0.x.
/// This causes clang to mangle dependent nested names incorrectly.
Ver14,

/// Conform to the underlying platform's C and C++ ABIs as closely
/// as we can.
Latest
Expand Down Expand Up @@ -527,6 +531,12 @@ class LangOptions : public LangOptionsBase {
return CPlusPlus || C2x || DisableKNRFunctions;
}

/// Returns true if implicit function declarations are allowed in the current
/// language mode.
bool implicitFunctionsAllowed() const {
return !requiresStrictPrototypes() && !OpenCL;
}

/// Check if return address signing is enabled.
bool hasSignReturnAddress() const {
return getSignReturnAddressScope() != SignReturnAddressScopeKind::None;
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/TargetOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,11 @@ class TargetOptions {
/// The version of the darwin target variant SDK which was used during the
/// compilation.
llvm::VersionTuple DarwinTargetVariantSDKVersion;

/// The validator version for dxil.
std::string DxilValidatorVersion;
};

} // end namespace clang
} // end namespace clang

#endif
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ TYPE_TRAIT_1(__has_unique_object_representations,
KEYWORD(__underlying_type , KEYCXX)

// Clang-only C++ Type Traits
TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX)
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)

// Embarcadero Expression Traits
Expand Down
11 changes: 9 additions & 2 deletions clang/include/clang/Driver/Action.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ class Action {
/// The Offloading architecture associated with this action.
const char *OffloadingArch = nullptr;

/// The Offloading toolchain associated with this device action.
const ToolChain *OffloadingToolChain = nullptr;

Action(ActionClass Kind, types::ID Type) : Action(Kind, ActionList(), Type) {}
Action(ActionClass Kind, Action *Input, types::ID Type)
: Action(Kind, ActionList({Input}), Type) {}
Expand Down Expand Up @@ -184,7 +187,8 @@ class Action {

/// Set the device offload info of this action and propagate it to its
/// dependences.
void propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch);
void propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch,
const ToolChain *OToolChain);

/// Append the host offload info of this action and propagate it to its
/// dependences.
Expand All @@ -205,10 +209,13 @@ class Action {

OffloadKind getOffloadingDeviceKind() const { return OffloadingDeviceKind; }
const char *getOffloadingArch() const { return OffloadingArch; }
const ToolChain *getOffloadingToolChain() const {
return OffloadingToolChain;
}

/// Check if this action have any offload kinds. Note that host offload kinds
/// are only set if the action is a dependence to a host offload action.
bool isHostOffloading(OffloadKind OKind) const {
bool isHostOffloading(unsigned int OKind) const {
return ActiveOffloadKindMask & OKind;
}
bool isDeviceOffloading(OffloadKind OKind) const {
Expand Down
42 changes: 27 additions & 15 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -906,14 +906,6 @@ def fconvergent_functions : Flag<["-"], "fconvergent-functions">, Group<f_Group>
def gpu_use_aux_triple_only : Flag<["--"], "gpu-use-aux-triple-only">,
InternalDriverOpt, HelpText<"Prepare '-aux-triple' only without populating "
"'-aux-target-cpu' and '-aux-target-feature'.">;
def cuda_device_only : Flag<["--"], "cuda-device-only">,
HelpText<"Compile CUDA code for device only">;
def cuda_host_only : Flag<["--"], "cuda-host-only">,
HelpText<"Compile CUDA code for host only. Has no effect on non-CUDA "
"compilations.">;
def cuda_compile_host_device : Flag<["--"], "cuda-compile-host-device">,
HelpText<"Compile CUDA code for both host and device (default). Has no "
"effect on non-CUDA compilations.">;
def cuda_include_ptx_EQ : Joined<["--"], "cuda-include-ptx=">, Flags<[NoXarchOption]>,
HelpText<"Include PTX for the following GPU architecture (e.g. sm_35) or 'all'. May be specified more than once.">;
def no_cuda_include_ptx_EQ : Joined<["--"], "no-cuda-include-ptx=">, Flags<[NoXarchOption]>,
Expand All @@ -927,6 +919,8 @@ def cuda_gpu_arch_EQ : Joined<["--"], "cuda-gpu-arch=">, Flags<[NoXarchOption]>,
Alias<offload_arch_EQ>;
def hip_link : Flag<["--"], "hip-link">,
HelpText<"Link clang-offload-bundler bundles for HIP">;
def no_hip_rt: Flag<["-"], "no-hip-rt">,
HelpText<"Do not link against HIP runtime libraries">;
def no_offload_arch_EQ : Joined<["--"], "no-offload-arch=">, Flags<[NoXarchOption]>,
HelpText<"Remove CUDA/HIP offloading device architecture (e.g. sm_35, gfx906) from the list of devices to compile for. "
"'all' resets the list to its default value.">;
Expand Down Expand Up @@ -2532,10 +2526,27 @@ defm openmp_optimistic_collapse : BoolFOption<"openmp-optimistic-collapse",
PosFlag<SetTrue, [CC1Option]>, NegFlag<SetFalse>, BothFlags<[NoArgumentUnused, HelpHidden]>>;
def static_openmp: Flag<["-"], "static-openmp">,
HelpText<"Use the static host OpenMP runtime while linking.">;
def offload_new_driver : Flag<["--"], "offload-new-driver">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Use the new driver for offloading compilation.">;
def no_offload_new_driver : Flag<["--"], "no-offload-new-driver">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Don't Use the new driver for offloading compilation.">;
def offload_device_only : Flag<["--"], "offload-device-only">,
HelpText<"Only compile for the offloading device.">;
def offload_host_only : Flag<["--"], "offload-host-only">,
HelpText<"Only compile for the offloading host.">;
def offload_host_device : Flag<["--"], "offload-host-device">,
HelpText<"Only compile for the offloading host.">;
def cuda_device_only : Flag<["--"], "cuda-device-only">, Alias<offload_device_only>,
HelpText<"Compile CUDA code for device only">;
def cuda_host_only : Flag<["--"], "cuda-host-only">, Alias<offload_host_only>,
HelpText<"Compile CUDA code for host only. Has no effect on non-CUDA compilations.">;
def cuda_compile_host_device : Flag<["--"], "cuda-compile-host-device">, Alias<offload_host_device>,
HelpText<"Compile CUDA code for both host and device (default). Has no "
"effect on non-CUDA compilations.">;
def fopenmp_new_driver : Flag<["-"], "fopenmp-new-driver">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Use the new driver for OpenMP offloading.">;
def fno_openmp_new_driver : Flag<["-"], "fno-openmp-new-driver">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Don't use the new driver for OpenMP offloading.">;
Alias<no_offload_new_driver>, HelpText<"Don't use the new driver for OpenMP offloading.">;
def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Disable tail call optimization, keeping the call stack accurate">,
MarshallingInfoFlag<CodeGenOpts<"DisableTailCalls">>;
Expand Down Expand Up @@ -6725,20 +6736,21 @@ def _SLASH_ZW : CLJoined<"ZW">;

def dxc_Group : OptionGroup<"<clang-dxc options>">, Flags<[DXCOption]>,
HelpText<"dxc compatibility options">;

class DXCJoinedOrSeparate<string name> : Option<["/", "-"], name,
KIND_JOINED_OR_SEPARATE>, Group<dxc_Group>, Flags<[DXCOption, NoXarchOption]>;

def dxc_help : Option<["/", "-", "--"], "help", KIND_JOINED>,
Group<dxc_Group>, Flags<[DXCOption, NoXarchOption]>, Alias<help>,
HelpText<"Display available options">;


def Fo : DXCJoinedOrSeparate<"Fo">, Alias<o>,
HelpText<"Output object file.">;

HelpText<"Output object file">;
def dxil_validator_version : Option<["/", "-"], "validator-version", KIND_SEPARATE>,
Group<dxc_Group>, Flags<[DXCOption, NoXarchOption, CC1Option, HelpHidden]>,
HelpText<"Override validator version for module. Format: <major.minor>;"
"Default: DXIL.dll version or current internal version">,
MarshallingInfoString<TargetOpts<"DxilValidatorVersion">>;
def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">,
HelpText<"Set target profile.">,
HelpText<"Set target profile">,
Values<"ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, ps_6_7,"
"vs_6_0, vs_6_1, vs_6_2, vs_6_3, vs_6_4, vs_6_5, vs_6_6, vs_6_7,"
"gs_6_0, gs_6_1, gs_6_2, gs_6_3, gs_6_4, gs_6_5, gs_6_6, gs_6_7,"
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Driver/ToolChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,11 @@ class ToolChain {
virtual llvm::SmallVector<BitCodeLibraryInfo, 12>
getHIPDeviceLibs(const llvm::opt::ArgList &Args) const;

/// Add the system specific linker arguments to use
/// for the given HIP runtime library type.
virtual void AddHIPRuntimeLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {}

/// Return sanitizers which are available in this toolchain.
virtual SanitizerMask getSupportedSanitizers() const;

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -11974,6 +11974,10 @@ class Sema final {
QualType CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
ExprResult &RHS,
SourceLocation QuestionLoc);

QualType CheckSizelessVectorConditionalTypes(ExprResult &Cond,
ExprResult &LHS, ExprResult &RHS,
SourceLocation QuestionLoc);
QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2,
bool ConvertArgs = true);
QualType FindCompositePointerType(SourceLocation Loc,
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,18 @@ class ASTReader
/// been completed.
std::deque<PendingDeclContextInfo> PendingDeclContextInfos;

template <typename DeclTy>
using DuplicateObjCDecls = std::pair<DeclTy *, DeclTy *>;

/// When resolving duplicate ivars from Objective-C extensions we don't error
/// out immediately but check if can merge identical extensions. Not checking
/// extensions for equality immediately because ivar deserialization isn't
/// over yet at that point.
llvm::SmallMapVector<DuplicateObjCDecls<ObjCCategoryDecl>,
llvm::SmallVector<DuplicateObjCDecls<ObjCIvarDecl>, 4>,
2>
PendingObjCExtensionIvarRedeclarations;

/// The set of NamedDecls that have been loaded, but are members of a
/// context that has been merged into another context where the corresponding
/// declaration is either missing or has not yet been loaded.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,6 @@ class ProgramState : public llvm::FoldingSetNode {
Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
bool IsVirtual) const;

/// Get the lvalue for a parameter.
Loc getLValue(const Expr *Call, unsigned Index,
const LocationContext *LC) const;

/// Get the lvalue for a variable reference.
Loc getLValue(const VarDecl *D, const LocationContext *LC) const;

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Testing/TestAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ struct TestInputs {
/// Extra argv to pass to clang -cc1.
std::vector<std::string> ExtraArgs = {};

/// Extra virtual files that are available to be #included.
/// Keys are plain filenames ("foo.h"), values are file content.
llvm::StringMap<std::string> ExtraFiles = {};

/// By default, error diagnostics during parsing are reported as gtest errors.
/// To suppress this, set ErrorOK or include "error-ok" in a comment in Code.
/// In either case, all diagnostics appear in TestAST::diagnostics().
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ class DependencyScanningWorkerFilesystem : public llvm::vfs::ProxyFileSystem {
DependencyScanningWorkerFilesystem(
DependencyScanningFilesystemSharedCache &SharedCache,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings)
ExcludedPreprocessorDirectiveSkipMapping &PPSkipMappings)
: ProxyFileSystem(std::move(FS)), SharedCache(SharedCache),
PPSkipMappings(PPSkipMappings) {}

Expand Down Expand Up @@ -398,10 +398,10 @@ class DependencyScanningWorkerFilesystem : public llvm::vfs::ProxyFileSystem {
/// The local cache is used by the worker thread to cache file system queries
/// locally instead of querying the global cache every time.
DependencyScanningFilesystemLocalCache LocalCache;
/// The optional mapping structure which records information about the
/// The mapping structure which records information about the
/// excluded conditional directive skip mappings that are used by the
/// currently active preprocessor.
ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings;
ExcludedPreprocessorDirectiveSkipMapping &PPSkipMappings;
/// The set of files that should not be minimized.
llvm::DenseSet<llvm::sys::fs::UniqueID> NotToBeMinimized;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class DependencyScanningService {
public:
DependencyScanningService(ScanningMode Mode, ScanningOutputFormat Format,
bool ReuseFileManager = true,
bool SkipExcludedPPRanges = true,
bool OptimizeArgs = false);

ScanningMode getMode() const { return Mode; }
Expand All @@ -57,8 +56,6 @@ class DependencyScanningService {

bool canReuseFileManager() const { return ReuseFileManager; }

bool canSkipExcludedPPRanges() const { return SkipExcludedPPRanges; }

bool canOptimizeArgs() const { return OptimizeArgs; }

DependencyScanningFilesystemSharedCache &getSharedCache() {
Expand All @@ -69,10 +66,6 @@ class DependencyScanningService {
const ScanningMode Mode;
const ScanningOutputFormat Format;
const bool ReuseFileManager;
/// Set to true to use the preprocessor optimization that skips excluded PP
/// ranges by bumping the buffer pointer in the lexer instead of lexing the
/// tokens in the range until reaching the corresponding directive.
const bool SkipExcludedPPRanges;
/// Whether to optimize the modules' command-line arguments.
const bool OptimizeArgs;
/// The global file system cache.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class DependencyScanningWorker {

private:
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
std::unique_ptr<ExcludedPreprocessorDirectiveSkipMapping> PPSkipMappings;
ExcludedPreprocessorDirectiveSkipMapping PPSkipMappings;

/// The physical filesystem overlaid by `InMemoryFS`.
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> RealFS;
Expand Down
17 changes: 0 additions & 17 deletions clang/include/clang/Tooling/Inclusions/HeaderIncludes.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,23 +129,6 @@ class HeaderIncludes {
llvm::Regex IncludeRegex;
};

/// \returns a regex that can match various styles of C++ includes.
/// For example:
/// \code
/// #include <foo.h>
/// @import bar;
/// #include "bar.h"
/// \endcode
llvm::Regex getCppIncludeRegex();

/// \returns the last match in the list of matches that is not empty.
llvm::StringRef getIncludeNameFromMatches(
const llvm::SmallVectorImpl<llvm::StringRef> &Matches);

/// \returns the given include name and removes the following symbols from the
/// beginning and ending of the include name: " > < ;
llvm::StringRef trimInclude(llvm::StringRef IncludeName);

} // namespace tooling
} // namespace clang

Expand Down
9 changes: 8 additions & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11762,7 +11762,14 @@ void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) {

unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const {
auto I = MangleNumbers.find(ND);
return I != MangleNumbers.end() ? I->second : 1;
unsigned Res = I != MangleNumbers.end() ? I->second : 1;
if (!LangOpts.CUDA || LangOpts.CUDAIsDevice)
return Res;

// CUDA/HIP host compilation encodes host and device mangling numbers
// as lower and upper half of 32 bit integer.
Res = CUDAMangleDeviceNameInHostCompilation ? Res >> 16 : Res & 0xFFFF;
return Res > 1 ? Res : 1;
}

void ASTContext::setStaticLocalNumber(const VarDecl *VD, unsigned Number) {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4705,8 +4705,8 @@ bool RecordDecl::isMsStruct(const ASTContext &C) const {
return hasAttr<MSStructAttr>() || C.getLangOpts().MSBitfields == 1;
}

void RecordDecl::reorderFields(const SmallVectorImpl<Decl *> &Fields) {
std::tie(FirstDecl, LastDecl) = DeclContext::BuildDeclChain(Fields, false);
void RecordDecl::reorderDecls(const SmallVectorImpl<Decl *> &Decls) {
std::tie(FirstDecl, LastDecl) = DeclContext::BuildDeclChain(Decls, false);
LastDecl->NextInContextAndBits.setPointer(nullptr);
setIsRandomized(true);
}
Expand Down
11 changes: 8 additions & 3 deletions clang/lib/AST/DeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1647,6 +1647,11 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {

ObjCIvarDecl *curIvar = nullptr;
if (!data().IvarList) {
// Force ivar deserialization upfront, before building IvarList.
(void)ivar_empty();
for (const auto *Ext : known_extensions()) {
(void)Ext->ivar_empty();
}
if (!ivar_empty()) {
ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
data().IvarList = *I; ++I;
Expand Down Expand Up @@ -1838,8 +1843,8 @@ ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
ObjCIvarDecl::None, nullptr, false);
}

const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
const auto *DC = cast<ObjCContainerDecl>(getDeclContext());
ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() {
auto *DC = cast<ObjCContainerDecl>(getDeclContext());

switch (DC->getKind()) {
default:
Expand All @@ -1849,7 +1854,7 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {

// Ivars can only appear in class extension categories.
case ObjCCategory: {
const auto *CD = cast<ObjCCategoryDecl>(DC);
auto *CD = cast<ObjCCategoryDecl>(DC);
assert(CD->IsClassExtension() && "invalid container for ivar!");
return CD->getClassInterface();
}
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ class CXXNameMangler {
private:

bool mangleSubstitution(const NamedDecl *ND);
bool mangleSubstitution(NestedNameSpecifier *NNS);
bool mangleSubstitution(QualType T);
bool mangleSubstitution(TemplateName Template);
bool mangleSubstitution(uintptr_t Ptr);
Expand All @@ -456,6 +457,11 @@ class CXXNameMangler {

addSubstitution(reinterpret_cast<uintptr_t>(ND));
}
void addSubstitution(NestedNameSpecifier *NNS) {
NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS);

addSubstitution(reinterpret_cast<uintptr_t>(NNS));
}
void addSubstitution(QualType T);
void addSubstitution(TemplateName Template);
void addSubstitution(uintptr_t Ptr);
Expand Down Expand Up @@ -2036,12 +2042,21 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
return;

case NestedNameSpecifier::Identifier:
// Clang 14 and before did not consider this substitutable.
bool Clang14Compat = getASTContext().getLangOpts().getClangABICompat() <=
LangOptions::ClangABI::Ver14;
if (!Clang14Compat && mangleSubstitution(qualifier))
return;

// Member expressions can have these without prefixes, but that
// should end up in mangleUnresolvedPrefix instead.
assert(qualifier->getPrefix());
manglePrefix(qualifier->getPrefix());

mangleSourceName(qualifier->getAsIdentifier());

if (!Clang14Compat)
addSubstitution(qualifier);
return;
}

Expand Down Expand Up @@ -6009,6 +6024,14 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
}

bool CXXNameMangler::mangleSubstitution(NestedNameSpecifier *NNS) {
assert(NNS->getKind() == NestedNameSpecifier::Identifier &&
"mangleSubstitution(NestedNameSpecifier *) is only used for "
"identifier nested name specifiers.");
NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS);
return mangleSubstitution(reinterpret_cast<uintptr_t>(NNS));
}

/// Determine whether the given type has any qualifiers that are relevant for
/// substitutions.
static bool hasMangledSubstitutionQualifiers(QualType T) {
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/AST/MicrosoftCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ class MSHIPNumberingContext : public MicrosoftNumberingContext {
unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {
return DeviceCtx->getManglingNumber(CallOperator);
}

unsigned getManglingNumber(const TagDecl *TD,
unsigned MSLocalManglingNumber) override {
unsigned DeviceN = DeviceCtx->getManglingNumber(TD, MSLocalManglingNumber);
unsigned HostN =
MicrosoftNumberingContext::getManglingNumber(TD, MSLocalManglingNumber);
if (DeviceN > 0xFFFF || HostN > 0xFFFF) {
DiagnosticsEngine &Diags = TD->getASTContext().getDiagnostics();
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error, "Mangling number exceeds limit (65535)");
Diags.Report(TD->getLocation(), DiagID);
}
return (DeviceN << 16) | HostN;
}
};

class MSSYCLNumberingContext : public MicrosoftNumberingContext {
Expand Down
Loading